In this article:
Foresight Analytics Platform features loading and use of external assemblies. The executed assemblies are loaded to the application domain and kept there until the entire application end. If external assembly methods execute dynamic loading of other assemblies, those assemblies are also included into the current application domain and are there until the application work is completed. Because of that the situation described below may take place.
NOTE. .NET Framework uses various Load* methods of the System.Reflection.Assembly class for dynamic loading of assemblies. Dynamic loading is also executed on work of some system assemblies, particularly on serialization using System.Xml.Serialization.XmlSerializer.
For instance, a developed external assembly is loaded to the .NET repository assembly, let us name it the A assembly. After any modifications an external assembly is loaded to another .NET repository assembly named the B assembly. At the same time names of all types implemented in the external assembly and the name of the assembly are left as they are. Any method of external assembly executes the dynamic loading and work with different types of another external assembly that is the Test assembly. When the A and B assemblies are used, the following is executed in repository:
When addressing the A assembly it is to be load to the application domain. Executing the method which executes dynamic loading, the Test assembly is loaded to the application domain. When finishing assemblies they are still kept in the application domain.
When addressing the B assembly it is also loaded to the current application domain. Executing the method which executes dynamic loading, it is checked if the domain already has the Test assembly and at the same time the assembly loaded during the work with the A assembly is to be found. The A and B assemblies have the same identity but for the runtime environment have absolutely different types.
When working in the B assembly with the Test assembly types an error of types incompatibility is displayed because the found assembly is derivative of the A assembly and does not match.
This problem can be solved by timely loading assemblies from the application domain but because of Foresight Analytics Platform assemblies implementation, this problem remains unsolved. It will be solved in later versions of Foresight Analytics Platform.
If dynamic loading is executed in the external assembly code, it is recommended to refuse it and use the links to the assembly in project settings.
Use the way to bypass described below if the serializer uses the XML (XmlSerializer) in the extended assembly.
There is the following bypass to solve the problem with serializer which dynamically loads during its work the assembly with serialized types to the memory: it is required to merge the source assembly and the XML serialization assembly when modifying the code for serializer initializer beforehand (modified code is given in the example below). This enables to use serializer stored in the assembly body and initialized for the assembly sample to perform with.
The XML serialization assembly contains the shell for the XML serializer tool. To create a serialization assembly, use the SGen utility provided with Microsoft Visual Studio. The command to create the serialization assembly: SGen <AssemblyName>.DLL. When this command is executed, the <AssemblyName>.XmlSerializers.dll library is created in the directory of assembly library. To merge two assemblies, use the ILMerge utility (the utility can be downloaded at http://www.microsoft.com/). The command to merge assemblies: ILMerge /t:library /out: <EndAssembly>.dll <AssemblyName>.dll <AssemblyName>.XmlSerializers.dll. The output merged assembly and its different modifications can be loaded to different .NET repository assemblies and used in parallel.
Consider assembly merging in the following example:
There is an assembly developed in the C# language in the Microsoft Visual Studio environment. The assembly body includes the following code:
using System;
using System.Xml;
using System.Xml.Serialization;
namespace TestAssembly
{
[Serializable()]
public class Test
{
//...
//Object serialization in XML
public void ToXML(string path)
{
//...
XmlSerializer s = new XmlSerializer(this.GetType());
//...
}
//...
// Object deserialization from XML
public Test FromXml(string path)
{
//...
XmlSerializer s = new XmlSerializer(this.GetType());
//...
}
//...
}
}
The ToXML procedure is used to serialize the current Test class object to XML. The FromXml function deserializes the object from file which results in the Test class object. To use the specified assembly and a number of its modifications in Foresight Analytics Platform, change the code to initialize the serializer as follows:
XmlSerializer s = (XmlSerializer)Assembly.GetExecutingAssembly().CreateInstance("Microsoft.Xml.Serialization.GeneratedAssembly.TestSerializer");
At this stage the Microsoft.Xml.Serialization.GeneratedAssembly.TestSerializer type is not yet existing and it is getting available after getting the assembly serialization. Compile the assembly. To generate the serialization assembly, go to the \bin\Debug\ project folder and execute the following command in the command line:
SGen TestAssembly.dll
NOTE. The path to the SGen utility must be added to the Path system variable in the operating system.
The TestAssembly.XmlSerializers.dll library is to be created in the same folder when executing the command. Viewing the contents of this library enables the user to notice the Microsoft.Xml.Serialization.GeneratedAssembly namespace with included TestSerializer class. This class is used to initialize serializer.
Install the ILMerge utility and execute the following command to merge assemblies:
ILMerge /t:library /out:TestXAssembly.dll TestAssembly.dll TestAssembly.XmlSerializers.dll
After the command execution the TestXAssembly.dll merged assembly is to be created. This assembly can be loaded to different .NET repository assemblies.
The specified commands to generalize serialization assemblies and merged assemblies can be changed by modifications in the project file of developed assembly. In the end of the project file there is the space to form two sections: <Target Name="BeforeBuild"> and <Target Name="AfterBuild">. In this case, let us create the <Target Name="AfterBuild"> section and specify the following code in it:
<Target Name="AfterBuild" DependsOnTargets="AssignTargetPaths;Compile;ResolveKeySource" Inputs="$(MSBuildAllProjects);@(IntermediateAssembly)" Outputs="$(OutputPath)$(_SGenDllName)">
<!-- Delete serialization file if it already exists -->
<Delete Files="$(TargetDir)$(TargetName).XmlSerializers.dll" ContinueOnError="true" />
<!-- Create new serialization file -->
<SGen BuildAssemblyName="$(TargetFileName)" BuildAssemblyPath="$(OutputPath)" References="@(ReferencePath)" ShouldGenerateSerializer="true" UseProxyTypes="false" KeyContainer="$(KeyContainerName)" KeyFile="$(KeyOriginatorFile)" DelaySign="$(DelaySign)" ToolPath="$(TargetFrameworkSDKToolsDirectory)" Platform="$(Platform)">
<Output TaskParameter="SerializationAssembly" ItemName="SerializationAssembly" />
</SGen>
<!-- Create temporary folder for the merged assembly -->
<MakeDir Directories="$(TargetDir)merged"/>
<Exec Command="ILMerge /t:library /out:$(TargetDir)merged\$(TargetFileName) $(TargetDir)$(TargetFileName) $(TargetDir)$(TargetName).XmlSerializers.dll"/>
<!-- Delete all files created during compilation -->
<Exec Command="del $(TargetDir)$(TargetName)*.* /q"/>
<!-- Move merged assembly to the main project folder with stored compilation results -->
<Exec Command="move $(TargetDir)merged\*.* $(TargetDir)"/>
<!-- Delete temporary folder -->
<RemoveDir Directories="$(TargetDir)merged"/>
</Target>
These changes enable the user to execute all operations with assemblies during the compilation of the current project.
See also: