C#: Loading Dynamic Assemblies Into Other AppDomains

So you have generated dynamic assemblies (like here) and want to load the assembly into a new (or at least another than the current) AppDomain? Well, there’s a catch. You cannot share dynamic assemblies across AppDomains (easily)…Consider the following code:

// Create a new AppDomain to load the dynamic assembly into
var appDomain = AppDomain.CreateDomain("mynewappdomain", null, new AppDomainSetup
{
    ShadowCopyFiles = "true",
    LoaderOptimization = LoaderOptimization.MultiDomainHost
});

// Generate a dynamic assembly and get its bytes.
var rawAssemblyBytes = GenerateDynamicAssembly();

// Load the dynamic assembly into the new AppDomain
appDomain.Load(rawAssemblyBytes);

In the code above, I’m creating a new dynamic assembly and trying to load it into a new AppDomain. The last code line throws an exception:

An unhandled exception of type ‘System.IO.FileNotFoundException’ occurred in ConsoleApplication4.exe

Additional information: Could not load file or assembly ‘MyDynamicAssembly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null’ or one of its dependencies. The system cannot find the file specified.

So what’s happening here? Honestly, I’m not very sure. Looking at the Fusion logs leads me to some assumptions, but they might be very wrong so I’m not sharing them here 🙂 But the point of this post is to show a solution…

So how can we load the dynamic assembly into the other AppDomain? The trick is to call “AppDomain.Load” from inside the AppDomain itself. So here’s some sample code:

using System;
using System.IO;

namespace ConsoleApplication4
{
    internal class Program
    {
        private static void Main()
        {
            var bytes = GenerateAssemblyAndGetRawBytes();

            var appDomain = AppDomain.CreateDomain("mynewappdomain", null, new AppDomainSetup
            {
                ShadowCopyFiles = "true",
                LoaderOptimization = LoaderOptimization.MultiDomainHost
            });

            var assmblyLoaderType = typeof(AssmeblyLoader);
            var assemblyLoader = (IAssemblyLoader)appDomain.CreateInstanceFromAndUnwrap(assmblyLoaderType.Assembly.Location, assmblyLoaderType.FullName);
            assemblyLoader.Load(bytes);
        }

        private static byte[] GenerateAssemblyAndGetRawBytes()
        {
            // For testing purposes, just load any assembly from disk.
            var path = @"c:\tmp\ConsoleApplication4\ClassLibrary1\bin\debug\ClassLibrary1.dll";
            return File.ReadAllBytes(path);
        }
    }

    public interface IAssemblyLoader
    {
        void Load(byte[] bytes);
    }

    public class AssmeblyLoader : MarshalByRefObject, IAssemblyLoader
    {
        public void Load(byte[] bytes)
        {
            var assembly = AppDomain.CurrentDomain.Load(bytes);

            // do what you need to do with the assembly
        }
    }
}

Freelance full-stack .NET and JS developer and architect. Located near Cologne, Germany.

Leave a Reply

Your email address will not be published. Required fields are marked *