In this article:
Foresight Analytics Platform features loading and use of external assemblies. Performed assemblies are loaded to the application domain and kept there until the entire application end. If dynamic loading of other assemblies is performed in methods of an external assembly, then these assemblies get in the domain of the current application and stay there till it is finished. Because of that the situation described below can take place.
For instance, developed external assembly is loaded to the .NET repository assembly, lets 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 it is. Any method of external assembly performs the dynamic load 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 performed in repository:
When appealing to the "A" assembly it is to be load to the application domain. Executing the method which performs the dynamic load, the Test assembly is loaded to the application domain. When finishing assemblies they are still kept in the application domain.
When appealing to the "B" assembly it is also loaded to the current application domain. Performing the method which performs the dynamic load, it is checked whether domain already have the Test loaded 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. This problem is to be solved in latest versions of Prognoz Platform.
If the dynamic loading is performed in the code of external assembly, it is recommended to refuse of it and use the reference 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 way of 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 initial assembly and the XML serialization assembly when modifying the code for serializator 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 serializator tool. To create a serialization assembly use the SGen utility, provided with the Microsoft Visual Studio. Command to create the serialization assembly: SGen <AssemblyName>.DLL. When the command is executed, the <AssemblyName>.XmlSerializers.dll library is created in the directory of assembly library. To merge two assemblies use the ILMerge program (The program can be downloaded from the http://www.microsoft.com/). The command to merge assemblies: ILMerge /t:library /out: <EndAssembly>.dll <AssemblyName>.dll <AssemblyName>.XmlSerializers.dll. The resulting merged assembly and its different modifications can be loaded to the different .NET repository assemblies and used in parallel.
Consider the assembly merge process 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 performs the object deserialization from file which result is the Test class object. To use the specified assembly and a number of its modifications is Foresight Analytics Platform, change the code to initialize the serializer as follows:
XmlSerializer s = (XmlSerializer)Assembly.GetExecutingAssembly().CreateInstance("Microsoft.Xml.Serialization.GeneratedAssembly.TestSerializer");
On this stage the "Microsoft.Xml.Serialization.GeneratedAssembly.TestSerializer" type is not yet exist and it is getting available after obtaining the assembly serialization. Copy the assembly. To generate the serialization assembly go to the \bin\Debug\ project folder and in the command line perform the following command:
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 at the same folder when executing the command. Viewing the contents of this library, the Microsoft.Xml.Serialization.GeneratedAssembly namespace with included TestSerializer class can be found. This class is used to initialize serializer.
Install the ILMerge programm and perform 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.
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 is the space to form two sections: <Target Name="BeforeBuild"> and <Target Name="AfterBuild">. In this case, lets 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 is already exist -->
<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 enables the user to perform all operations over assemblies during the compilation of the current project.
See also: