C#: Loading Dynamic Assemblies Into Other AppDomains

So you have generated a dynamic assembly (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
        }
    }
}

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s