============================================== 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 :doc:`../loading-ioc-configuration/loading-from-xml.generated` 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 .. code-block:: xml :linenos: 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 GetAssemblies()**. Below is a demonstration of using properties **AdditionalReferencedAssemblies** and **LoadedAssemblies** in **IoC.Configuration.DiContainerBuilder.FileBased.FileBasedConfigurationParameters** to add references to dynamically generated assembly. .. code-block:: csharp :linenos: 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 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) .WithoutPresetDiContainer() .RegisterModules().Start(); var autoImplementedInterfaceInstance = containerInfo.DiContainer.Resolve(); 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 :doc:`../xml-configuration-file/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 :doc:`../xml-configuration-file/autogenerated-services/element-auto-service-custom.generated` for details on element **autoServiceCustom**. .. code-block:: csharp :linenos: 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(), AccessLevel.Public, false, false); methodInfo.AddCodeLine("=> 10;"); } public void Validate(ICustomAutoGeneratedServiceInfo customAutoGeneratedServiceInfo) { } public void ValidateOnIoCContainerLoaded(IDiContainer diContainer, ICustomAutoGeneratedServiceInfo customAutoGeneratedServiceInfo) { } }