如何在应用程序域之间进行最佳通信?

39

我有一个应用程序需要在多个AppDomains之间发送大量的消息。我知道可以使用远程处理来实现这一点,但我也注意到了跨域委托。是否有人研究过这种问题?


使用命名管道的WCF对我来说似乎是最受欢迎的选择 - 这样我至少可以避免进入网络的必要性。谢谢大家! - open-collar
能否详细说明一下这个技术?例如,与使用AppDomains和MBRO(MarshalByRefObject)相比,使用命名管道的性能成本和易用性如何? - lysergic-acid
我手头没有任何数字,但使用二进制序列化器和命名管道使我能够在域之间实现几乎无缝通信。我想出了一个简单的消息总线,自那以后就能够轻松地忽略这个问题了。 - open-collar
6个回答

27

我在使用命名管道绑定的情况下取得了良好的成功。 使用命名管道不会产生网络流量,采用二进制编码,因此应该相当快,而且不会牺牲将来扩展场景中的分发能力。

编辑: 更详细的信息,请参考此处,其中包括一个实现示例的链接。


IPC允许进程相互通信并同步它们的操作,但不适用于应用程序域之间的通信。如果我有错误,请纠正我。 - Vikas Gupta

13
一个跨域委托只允许一个没有参数的void方法,它可能不是你想象中的那样有用。它只能用作简单的回调通知从一个应用程序域到另一个应用程序域,例如像InitComplete()这样的方法。

远程调用是唯一的选择,无论您将其称为WCF还是其他任何东西,传递可序列化类型或使用MBRO类型(MarshalByRefObjects)。它不像你想的那么难。

- Oisin


.NET 1.1 的远程代理对我来说已经有些陈旧了。是否有更新的替代方案用于跨应用程序域通信? - lysergic-acid
远程调用从未消失。它仍然被广泛使用。WCF的现代化是为了跨进程(IPC)调用。但对于应用程序域,一直都是远程调用。你可以使用命名管道来使用WCF,但我认为这样做麻烦。在我看来,远程调用更简便。 - x0n
1
@x0n,[Remoting是]一种保留用于向后兼容现有应用程序的传统技术,不建议用于新开发。分布式应用程序现在应该使用Windows Communication Foundation (WCF)进行开发。http://msdn.microsoft.com/library/72x4h507.aspx - Guillaume
1
@Guillaume 没错,我同意 - 我可能应该更清楚地区分一下,但那是四年前的事:D - x0n

10

我刚刚发现,你也可以使用AppDomain.SetData,但这只是一种方法,从主域到子域。

static void RunInChildDomain()
{
     AppDomain childDomain = AppDomain.CreateDomain("friendlyName");
     string parameterValue = "notmii";
     childDomain.SetData("parameter", parameterValue);
     childDomain.DoCallBack(PrintName);
}

static void PrintName()
{
     string Name = Convert.ToString(AppDomain.CurrentDomain.GetData("parameter"));
     Console.WriteLine(Name);
}

你还可以使用AppDomain.FirstChanceException事件在子应用域和主应用域之间创建基于异常的通信 :)


非常抱歉重提这个老问题,但是从父域到子域不仅仅只有一种方法。您可以像这样使用SetData: childDomain.SetData("domain", AppDomain.CurrentDomain); 然后在子域中执行GetData("domain")以进行另一次Set/GetData和DoCallBack操作。 - Nyuno

5

CallContext 可以在 AppDomains 之间传递数据:

   CallContext.LogicalSetData("Key", "My value");
   Console.WriteLine("{0} from {1}", CallContext.LogicalGetData("Key"),               
   AppDomain.CurrentDomain.FriendlyName);

   var appDomain = AppDomain.CreateDomain("Worker");
   appDomain.DoCallBack(() => Console.WriteLine("{0} from {1}", 
       CallContext.LogicalGetData("Key"), 
       AppDomain.CurrentDomain.FriendlyName));
   AppDomain.Unload(appDomain);

   CallContext.FreeNamedDataSlot("Key");

代码使用System.Runtime.Remoting.Messaging。我个人没有测量这种解决方案的性能。

这适用于任何两个域,而不仅仅是父子域。+1 - Chris Bordeman

3

这只是一个快速的想法,但我听说即使是跨域通信,从.NET 3.0开始,WCF也是推荐的方法。实际上,这很有道理,因为远程调用只是由WCF包装的另一种技术。


2
我想进一步解释xOn的回答。他建议使用WCF或MarshalByRefObject,但考虑到问题是关于AppDomains之间的通信,而不是进程之间的通信,我认为MBRO方法在实现上要简单得多,因此是正确的答案。
当我自己研究这个问题时,起初我很难理解子AppDomain如何与父AppDomain通信,直到我意识到可以将一个MBRO对象的句柄传递给子AppDomain,然后子AppDomain就可以解开该句柄以与父AppDomain(或任何其他AppDomain)进行通信。我在我的问题这里发布了一个解决方案。
后来我了解到,您可以定义一个接口,在一个复杂的类上实现该接口,然后仅传递接口的句柄。这可以大大减少可能需要加载子AppDomain的程序集的数量。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接