使用MarshalByRefObject在appdomains中传递数据

时间:2009-11-19 23:49:48

标签: c# .net appdomain marshalbyrefobject

我在两个.NET应用程序域之间传递一些数据时遇到了一些麻烦,我希望有人可以帮助我。

基本上我所拥有的是一个主应用程序( Main ),它将程序集 A B 加载到它的主域中,然后当我运行时插件( C Main B 上调用创建域方法,该方法会创建一个新域并加载 C B 的一个实例,因此 C 只能访问 B ,而不能访问其他人。

B 包含指向 Main 的IDispatch的指针,但只有在使用 C 将其加载到新域后才能获得它。我要做的是从 B 的新域实例发送指针的副本,并将其发送到仍在默认域中运行的 A

仅为记录我控制 A,B和C 但不是

很抱歉,如果这有点难以理解,我会尽力解释。

代码:

在A:

public class Tunnel : MarshalByRefObject
{
    public void SetPointer(int dispID)
    {
        IntPtr pointer = new IntPtr(dispID);
    }
}

在B:

//Call by Main after loading plug in but after A.dll is loaded.
public void CreateDomain()
{
  AppDomain maindomain= AppDomain.CurrentDomain;
  tunnel = (Tunnel)maindomain.CreateInstanceAndUnwrap(typeof(Tunnel).FullName,
                                                      typeof(Tunnel).FullName);

   AppDomain domain = base.CreateDomain(friendlyName, securityInfo, appDomainInfo);
   //Load assembly C (plug in) in domain.
   // C uses B so it loads a new instance of B into the domain also at the same time.

  // If I do this here it creates new instance of A but I need to use the one in
  // the main domain.
  //tunnel = (Tunnel)domain.CreateInstanceAndUnwrap(typeof(Tunnel).FullName,
                                                    typeof(Tunnel).FullName);
  tunnel.SetPointer(//Send data from B loaded in new domain.)

}

所以最后它看起来像这样:

默认域名:

  • Main.dll
  • A.DLL
  • B.DLL

插入域名:

  • B.DLL
  • C.dll

3 个答案:

答案 0 :(得分:8)

在上面的代码中,您正在调用

AppDomain.CurrentDomain.CreateInstanceAndUnwrap(...)

这只是在当前域中创建对象的一种循环方式,就像刚刚调用构造函数一样。您需要在远程域上调用该方法,即

AppDomain domain = AppDomain.Create(...)
Tunnel tunnel = (Tunnel)domain.CreateInstanceAndUnwrap(...)

如果您随后调用将在远程对象上运行的tunnel.SetPointer(...)。

答案 1 :(得分:0)

所以我想:

class B : MarshallByRef

,只需在A类中创建域中的对象:

AppDomain domain = ...
B inst = (B) domain.CreateInstanceAndUnwrap(typeof(B).Assembly.FullName, typeof(B).FullName);
inst.DoPlugin("C");

DoPlugin()方法将动态加载类型“C”并调用任何适当的方法。

答案 2 :(得分:0)

创建“子”域时,您可能必须复制搜索路径和证据(特别是在单元测试库下运行):

var dom = AppDomain.CreateDomain("NewDomain",
    AppDomain.CurrentDomain.Evidence, AppDomain.CurrentDomain.BaseDirectory,
    AppDomain.CurrentDomain.RelativeSearchPath, false);
try
{
    var tunnel = (MyMarshallByRef)dom.CreateInstanceAndUnwrap(
        typeof(MyMarshallByRef).Assembly.FullName,
        typeof(MyMarshallByRef).FullName);

    tunnel.DoStuff("data");
}
finally
{
    AppDomain.Unload(dom);
}

另请注意,DoStuff方法的任何参数及其返回的任何类型必须标记为[Serializable]