Sitation:
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?
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
Simply create remote host object in the main AppDomain
and pass it to the newly initialized child domain. Whenever the child want to send data to the host, use this remote host object.
// This class provides callbacks to the host app domain.
// As it is derived from MarshalByRefObject, it will be a remote object
// when passed to the children.
// if children are not allowed to reference the host, create an IHost interface
public class DomainHost : MarshalByRefObject
{
// send a message to the host
public void SendMessage(IChild sender, string message)
{
Console.WriteLine($"Message from child {sender.Name}: {message}");
}
// sends any object to the host. The object must be serializable
public void SendObject(IChild sender, object package)
{
Console.WriteLine($"Package from child {sender.Name}: {package}");
}
// there is no timeout for host
public override object InitializeLifetimeService()
{
return null;
}
}
I suspect that the children object you create already implement an interface so you can reference them from the main domain without loading their actual type. On initialization you can pass them the host object so after the initialization you can do callbacks from the children.
public interface IChild
{
void Initialize(DomainHost host);
void DoSomeChildishJob();
string Name { get; }
}
ChildExample.dll:
internal class MyChild : MarshalByRefObject, IChild
{
private DomainHost host;
public void Initialize(DomainHost host)
{
// store the remote host here so you will able to use it to send feedbacks
this.host = host;
host.SendMessage(this, "I am being initialized.")
}
public string Name { get { return "Dummy child"; } }
public void DoSomeChildishJob()
{
host.SendMessage(this, "Job started.")
host.SendObject(this, 42);
host.SendMessage(this, "Job finished.")
}
}
Usage:
var domain = AppDomain.CreateDomain("ChildDomain");
// use the proper assembly and type name.
// child is a remote object here, ChildExample.dll is not loaded into the main domain
IChild child = domain.CreateInstanceAndUnwrap("ChildExample", "ChildNamespace.MyChild") as IChild;
// pass the host to the child
child.Initialize(new DomainHost());
// now child can send feedbacks
child.DoSomeChildishJob();
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With