Troubleshooting Dynamically Generated Assembly

If configuration is loaded from configuration file, IoC.Configuration generates an assembly file which has a format DynamicallyGeneratedAssembly_timestamp.dll. Example is DynamicallyGeneratedAssembly_637851312217643417.dll.

Note

Refer to Loading from XML Configuration File for details on loading file based configuration

The dynamically generated assembly has classes for auto-generated services in elements autoService and autoServiceCustom under elements iocConfiguration/dependencyInjection/autoGeneratedServices and iocConfiguration/pluginsSetup/pluginSetup/dependencyInjection/autoGeneratedServices, as well as some other auto-generated classes.

Note

The file is deleted, and a new file is generated when the configuration is loaded. In the future an improvement might be implemented to re-generate the assembly only if the configuration changed.

The folder where the dynamically generated DLL file is saved is determined by the value of attribute path in element iocConfiguration/appDataDir as in example below

1
2
3
4
5
<iocConfiguration
    xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
    xsi:noNamespaceSchemaLocation="http://oroptimizer.com/IoC.Configuration/V2/IoC.Configuration.Schema.7579ADB2-0FBD-4210-A8CA-EE4B4646DB3F.xsd">
    <appDataDir path="TestFiles\AutogeneratedDlls\DynamicFiles_AutoServiceTests" />
</iocConfiguration>

Below are some situations when the auto-generated assembly might fail to load, when configuration is loaded:

  • The code generated for autoServiceCustom by an implementation of IoC.Configuration.ConfigurationFile.ICustomAutoServiceCodeGenerator has invalid code.
  • The dynamically generated assembly references classes from other assemblies, and the assemblies that contain the classes are not added as references to dynamically generated assembly. To better resolve this issue, the rules used to add references to dynamically generated assembly are outlined below.

How Referenced Assemblies are Added to Dynamically Generated Assembly

There are number of ways, listed below, that IoC.Configuration can be instructed to add references to dynamically generated assembly.

  • Add referenced assembly file paths in property AdditionalReferencedAssemblies in class IoC.Configuration.DiContainerBuilder.FileBased.FileBasedConfigurationParameters, an instanceof which is used when loading the configuration from xml file, as demonstrated below:

  • Make sure the assembly is included in property OROptimizer.ILoadedAssemblies LoadedAssemblies { get; } in IoC.Configuration.DiContainerBuilder.FileBased.FileBasedConfigurationParameters that is used to load the XML configuration file. The property LoadedAssemblies of IoC.Configuration.DiContainerBuilder.FileBased.FileBasedConfigurationParameters is initialized in constructor, and in most cases an implementation OROptimizer.AllLoadedAssemblies can be used as demonstrated in example below.

    Note

    OROptimizer.AllLoadedAssemblies returns all assemblies loaded into application domain in property System.Collections.Generic.IEnumerable<Assembly> GetAssemblies().

Below is a demonstration of using properties AdditionalReferencedAssemblies and LoadedAssemblies in IoC.Configuration.DiContainerBuilder.FileBased.FileBasedConfigurationParameters to add references to dynamically generated assembly.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
using System.IO;
using IoC.Configuration.DiContainerBuilder.FileBased;
using NUnit.Framework;
using OROptimizer.Utilities.Xml;
using TestsSharedLibrary;

namespace IoC.Configuration.Tests.DocumentationTests.ReferencesInDynamicAssembly;

[TestFixture]
public class FileBasedConfigurationParameters_AdditionalReferencedAssemblies
{
    [Test]
    public void FileBasedConfigurationParameters_AdditionalReferencedAssemblies_Demo()
    {
        TestsHelper.SetupLogger();

        var fileBasedConfigurationParameters = new FileBasedConfigurationParameters(
            new FileBasedConfigurationFileContentsProvider(
                Path.Combine(Helpers.TestsEntryAssemblyFolder, @"DocumentationTests\AutoServiceCustom\DemoIoCConfiguration_autoServiceCustom.xml")),
            Helpers.TestsEntryAssemblyFolder,
            // LoadedAssembliesForTests is an implementation of ILoadedAssemblies that has a method
            // "IEnumerable<Assembly> GetAssemblies()" that returns list of assemblies to add as references to
            // generate dynamic assembly.
            new LoadedAssembliesForTests())
        {
            AdditionalReferencedAssemblies = new []
            {
                // List additional assemblies that should be added to dynamically generated assembly as references
                Path.Combine(Helpers.GetTestFilesFolderPath(), @"DynamicallyLoadedDlls\TestProjects.DynamicallyLoadedAssembly1.dll"),
                Path.Combine(Helpers.GetTestFilesFolderPath(), @"DynamicallyLoadedDlls\TestProjects.DynamicallyLoadedAssembly2.dll")
            },
            AttributeValueTransformers = new[] {new FileFolderPathAttributeValueTransformer()},
            ConfigurationFileXmlDocumentLoaded = (sender, e) =>
                Helpers.EnsureConfigurationDirectoryExistsOrThrow(e.XmlDocument.SelectElement("/iocConfiguration/appDataDir").GetAttribute("path"))
        };

        var containerInfo = new DiContainerBuilder.DiContainerBuilder()
            .StartFileBasedDi(fileBasedConfigurationParameters, out _)
            .WithoutPresetDiContainer()
            .RegisterModules().Start();

        var autoImplementedInterfaceInstance = containerInfo.DiContainer.Resolve<IoC.Configuration.Tests.DocumentationTests.AutoServiceCustom.ISimpleAutoImplementedInterface1>();
        Assert.AreEqual(10, autoImplementedInterfaceInstance.GetValue());
    }
}
  • Include the assembly in one of iocConfiguration/assemblies/assembly elements in configuration file. All assemblies specified in iocConfiguration/assemblies/assembly elements are added as references to dynamically generated assembly. However when the assembly is loaded, referenced assemblies are loaded to domain only if types in these assemblies are used in dynamic assembly.

    Note

    Refer to Assemblies and Probing Paths for details on using iocConfiguration/assemblies/assembly elements.

  • Add referenced assemblies in implementation of method GenerateCSharp in interface IoC.Configuration.ConfigurationFile.ICustomAutoServiceCodeGenerator when providing an implementation of an interface specified in element autoServiceCustom. Look at example below.

    Note

    Refer to Element autoServiceCustom for details on element autoServiceCustom.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
using System;
using System.IO;
using IoC.Configuration.ConfigurationFile;
using IoC.Configuration.DiContainer;
using OROptimizer.DynamicCode;

namespace IoC.Configuration.Tests.DocumentationTests.ReferencesInDynamicAssembly;

public class CustomAutoServiceCodeGeneratorDemo : ICustomAutoServiceCodeGenerator
{
    public void GenerateCSharp(ICustomAutoGeneratedServiceInfo customAutoGeneratedServiceInfo,
        IDynamicAssemblyBuilder dynamicAssemblyBuilder,
        string generatedClassNamespace, string generatedClassName)
    {
        dynamicAssemblyBuilder.AddReferencedAssembly(
            Path.Combine(Helpers.GetTestFilesFolderPath(),
                @"DynamicallyLoadedDlls\TestProjects.DynamicallyLoadedAssembly1.dll"));

        dynamicAssemblyBuilder.AddReferencedAssembly(
            typeof(SharedServices.Interfaces.IInterface1));

        var classInfo = dynamicAssemblyBuilder.StartDynamicallyGeneratedClass(
            generatedClassName, generatedClassNamespace);

        var methodInfo = classInfo.StartMethod("GetValue", typeof(int),
            Array.Empty<IMethodParameterInfo>(),
            AccessLevel.Public, false, false);

        methodInfo.AddCodeLine("=> 10;");
    }

    public void Validate(ICustomAutoGeneratedServiceInfo customAutoGeneratedServiceInfo)
    {

    }

    public void ValidateOnIoCContainerLoaded(IDiContainer diContainer,
        ICustomAutoGeneratedServiceInfo customAutoGeneratedServiceInfo)
    {

    }
}