.NET Development
C# Parent AppDomain Loading Assembly When Transparent Proxy Cast
Gravatar is a globally recognized avatar based on your email address. C# Parent AppDomain Loading Assembly When Transparent Proxy Cast
  Jason
  All
  Nov 29, 2018 @ 01:52pm

Hello,

To start with a simply summary (hoping the solution is like), please note the following code/background:

[Creating New AppDomain - no issues here]

           AppDomain.CurrentDomain.TypeResolve += CurrentDomain_TypeResolve;
            AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
            AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve += CurrentDomain_ReflectionOnlyAssemblyResolve;
            _algoAppDomainSetup = new AppDomainSetup();
            _algoAppDomainSetup.PrivateBinPath = curDir;
            _algoAppDomainSetup.ApplicationBase = System.Environment.CurrentDirectory;
            _algoAppDomain = AppDomain.CreateDomain(AlgoAppDomain, null, _algoAppDomainSetup);

[Loading Assembly From Current Working Dir - seems to work fine, loads on in child AppDomain] I use a proxy class instantiated and executed in the child domain. var myObj = (MarshalByRefObject)AppDomain.CurrentDomain.CreateInstanceAndUnwrap("AssemblyName", "MyNameSpace.MyClass");

Problem Summary: The code successfully creates the child AppDomain, loads the DLL only in the child domain and I'm successfully able to return an instance of the class in question. However (and here's the latest pain), when I cast to the type I actually want to use in the parent domain (via "var newObj = (MyClass) proxy.GetInstance()"), the parent domain loads the DLL. Without the cast, the parent does not load the DLL and I can unload the child domain and delete the DLL.

Thank you in advance for any guidance. I of course can offer any other detail needed. Here's the proxy class if helpful:

    public class Proxy : MarshalByRefObject
    {
        public MarshalByRefObject GetAssembly(string assembly, AppDomain ad, byte[] bytes)
        {
            try
            {
                Assembly.Load("TargetAssemgly");
                var obj = (MarshalByRefObject)AppDomain.CurrentDomain.CreateInstanceAndUnwrap("TargetAssembly", "MyNameSpace.MyClass");
                
                return obj;    
            }
            catch (Exception ex)
            {
                ConsoleComms.WriteLine("Assembly Loading Error : " + ex.ToString());
            }

            return null; 
        }
    }

Gravatar is a globally recognized avatar based on your email address. re: C# Parent AppDomain Loading Assembly When Transparent Proxy Cast
  Rick Strahl
  Jason
  Nov 29, 2018 @ 02:37pm

That is all as you would expect. If you access a type that type has to be loaded by the AppDomain the type is running in - even if it's just a cast. So if you return a type that exists both in the child and parent and you cast the assembly will be loaded in both AppDomains. There's no way to avoid that if you use the strongly typed instance in both AppDomains.

There are a few ways around this:

  • Use interfaces
    Create a shared interface assembly and only pass back interfaces. The interface assembly would be only non-code so very light-weight, but it would still load in both AppDomains. Small though and not a big issue to leave around and because it wouldn't have executing code (only interfaces) it also wouldn't be a security issue.

  • Use dynamic or Reflection to access the type
    This avoids the type casting and allows .NET to just access the underlying marshalled objects running in the remote AppDomain. This has overhead of course and is tedious, but it works.

You need to also make sure that any marshalled type either support [Serializable] or is subclassed off of MarshalByRefObject otherwise cross domain communication won't work.

It really all depends on what you want to accomplish with the appdomain isolation. If you want code isolation you can achieve that and the cost of the extra assembly load in the parent AppDomain may not be an issue. if you want to be able to unload due to memory load, then you have to use something more dynamic to get at the proxy instance.

+++ Rick ---

© 1996-2018