Search code examples
c#ipcappdomain

Passing an object to receive callback from a child AppDomain created within a process to Default AppDomain


Sitation:

  1. I am creating a child app domain from my process to load an assembly.
  2. I am able to make calls to this AppDomain.
  3. I want to pass one object from my default process AppDomain to this newly created AppDomain, to receive callbacks from the assembly loaded in new AppDomain to my default AppDomain.

One way I found is to use the AppDomain.DoCallback method, however not sure how to get my host AppDomain in my child AppDomain?

Any body have any idea to achieve it?


Solution

  • The general idea is to pass to the newly created domain an instance of a class that is derived from MarshalByRefObject class. It will guarantee that this object will be marshaled by reference and not by value. It means that a proxy will be passed to the new domain and not the original object (this proxy will be generated for you by .NET framework).

    Later on when you call a method on this proxy, this call will be passed back to the original domain (a domain where the object was created). In other words a method will be executed in the original domain.

    Here is a code that shows this idea:

    public class Program
    {
        private static void Main(string[] args)
        {
            var listener = new Listener();
            var otherDomain = AppDomain.CreateDomain("otherDomain");
    
            var instance = (Loader)otherDomain.CreateInstanceAndUnwrap(Assembly.GetExecutingAssembly().FullName, typeof(Loader).FullName);
            instance.Init(listener);
        }
    }
    
    [Serializable]
    public class Loader 
        : MarshalByRefObject
    {
        public void Init(Listener listener)
        {
            Console.WriteLine($"[{nameof(Init)}] Hello from {AppDomain.CurrentDomain.FriendlyName} domain");
            listener.Callback();
        }
    }
    
    [Serializable]
    public class Listener 
        : MarshalByRefObject
    {
        public void Callback()
        {
            Console.WriteLine($"[{nameof(Callback)}] Hello from {AppDomain.CurrentDomain.FriendlyName} domain");
        }
    }
    

    When you run this code you will get the following result:

    [Init] Hello from otherDomain domain
    [Callback] Hello from Sandbox.vshost.exe domain
    

    It shows that Init method was executed in a new domain but a callback in the original one. Now comment 2 lines with : MarshalByRefObject and run the program one more time. This time Listener will be passed to the new domain by value and the result will be:

    [Init] Hello from Sandbox.vshost.exe domain
    [Callback] Hello from Sandbox.vshost.exe domain