Load Assembly into a new app domain but not CurrentDomain

1.9k views Asked by At

So my problem revolves around saving memory.

In essence I need to load an assembly in to a separate app domain other than the main/current domain, check for types within that assembly, and then unload the new domain when done.

Currently my solution is as follows:

AppDomain NewDomain = AppDomain.CreateDomain("newdomain");

foreach(string path in dllPaths) //string list of dll paths
{
    byte[] dllBytes = File.ReadAllBytes(dll);
    NewDomain.Load(dllBytes); //offending line
}

DoStuffWithNewDomain();
AppDomain.Unload(NewDomain);

The NewDomain.Load line seems to load the assembly into the new domain but also into the current domain of my program.

I used this link as a reference - http://www.csharp411.com/how-to-load-a-net-assembly-into-a-separate-appdomain-so-you-can-unload-it/

Many thanks :)

2

There are 2 answers

0
steve16351 On

As mentioned already, loading the assembly from bytes can only happen for the current app domain.

Here is one way to context-switch to make your target app domain the current one, using the DoCallBack method on the app domain (http://msdn.microsoft.com/en-us/library/system.appdomain.docallback%28v=vs.110%29.aspx).

After the assemblies are loaded you can then use the same method to inspect the assemblies and types of the new app domain, and create instances as necessary, before unloading it.

class Program
{
    static void Main(string[] args)
    {
        AppDomain newDomain = AppDomain.CreateDomain("NewDomain");
        List<string> dllPaths = new List<string>() { @"c:\dev\taglib-sharp.dll" };

        foreach (string dll in dllPaths)
        {
            AppDomainAsmLoader asmLoad = new AppDomainAsmLoader(File.ReadAllBytes(dll));
            newDomain.DoCallBack(new CrossAppDomainDelegate(asmLoad.LoadAsm));
        }

        newDomain.DoCallBack(new CrossAppDomainDelegate(DoWorkWithAppDomain));

        AppDomain.Unload(newDomain);
        Console.ReadKey();
    }

    public static void DoWorkWithAppDomain()
    {
        Assembly[] asms = AppDomain.CurrentDomain.GetAssemblies();
        foreach (Assembly asm in asms)
        {
            Type[] types = asm.GetTypes();
            foreach (Type type in types)
            {
                Console.WriteLine("Found the type: {0}", type.FullName);
            }
        }
    }

    [Serializable]
    public class AppDomainAsmLoader
    {
        private byte[] AsmData;  

        public AppDomainAsmLoader(byte[] data)
        {
            AsmData = data;
        }         

        public void LoadAsm()
        {
            Assembly asm = Assembly.Load(AsmData);
        }

    }
}
0
dbugger On

As Erik suggested, you need to use CreateInstanceAndWrap. Here's an example I did in VB a while back...

Private Function GetCoupler() As IBatchCoupler
        Dim CouplerProxy As IBatchCoupler = Nothing
        Try
            Dim DomainSetupInfo As AppDomainSetup = New AppDomainSetup()
            DomainSetupInfo.ConfigurationFile = Path.Combine(mFilePath, "web.config")
            DomainSetupInfo.ApplicationBase = Path.Combine(mFilePath, "bin")
            DomainSetupInfo.ShadowCopyFiles = "true"

Dim domain As AppDomain = AppDomain.CreateDomain("CoolDomain", AppDomain.CurrentDomain.Evidence, DomainSetupInfo)

            'Create remote object in new appDomain via the coupler interface
            'to avoid loading the design library into the calling application's primary appDomain
            CouplerProxy = domain.CreateInstanceFromAndUnwrap(Path.Combine(DomainSetupInfo.ApplicationBase, "Design.dll"), "BigApplication.Design.BatchCoupler")

        Catch ex As Exception

            ThisLogger.Error(ex)
        End Try
        Return CouplerProxy
    End Function