跨AppDomain通信问题
Posted
技术标签:
【中文标题】跨AppDomain通信问题【英文标题】:Inter-AppDomain communication problem 【发布时间】:2011-07-13 15:33:07 【问题描述】:我一直在用 C# 开发 Windows 服务。
此服务启动时会提供一组配置文件路径。对于这些文件中的每一个,该服务将使用该文件作为其ConfigurationFile
并将该文件的文件夹作为ApplicationBase
来启动一个AppDomain
。每个文件夹都有一个“bin”文件夹,设置为PrivateBinPath
。
这些文件夹中的“bin”文件夹包含一个与服务共享的小程序集,该程序集包含接口IServiceHost
。实现IServiceHost
接口的类的类型名称和程序集名称也是已知的。
整个CreateServiceHost
方法如下所示:-
public static IServiceHost CreateServiceHost(string configPath, string entryAssembly, string entryType)
IServiceHost host;
AppDomainSetup setupInfo = new AppDomainSetup();
setupInfo.ApplicationBase = Path.GetDirectoryName(configPath);
setupInfo.PrivateBinPath = Path.Combine(setupInfo.ApplicationBase, "bin");
setupInfo.ShadowCopyFiles = "true";
setupInfo.ConfigurationFile = configPath;
AppDomain appDomain = AppDomain.CreateDomain("Service for: " + setupInfo.ApplicationBase, AppDomain.CurrentDomain.Evidence, setupInfo);
object objHost = appDomain.CreateInstanceFromAndUnwrap(Path.Combine(setupInfo.PrivateBinPath, entryAssembly), entryType);
host = (IServiceHost)objHost;
return host;
IServiceHost
接口非常复杂:-
public interface IServiceHost
void Start();
void Stop();
服务 OnStart 包含如下内容:-
private List<IServiceHost> serviceHosts = new List<IServiceHost>();
protected override void OnStart(string[] args)
foreach (string configPaths in GetConfigPaths())
IServiceHost host = ServiceHostLoader.CreateServiceHost(configPath);
serviceHosts.Add(host);
host.Start();
OnStop
同样直截了当(为了简单起见,IServiceHost.Stop
正在阻塞调用)。
protected override void OnStop()
foreach (IServiceHost host in serviceHosts)
host.Stop();
这一切都很简单,在开发机器上进行测试时效果很好。但是在质量检查中,当它停止时我会遇到异常。在开发过程中,我们只在很短的时间内启动它,这一切似乎都运行良好。但是在 QA 中,该服务仅每 24 小时停止一次。在这种情况下,它始终无法正确停止。
以下是事件日志中最终结果的示例:-
事件类型:错误事件 资料来源:工作区服务活动 类别:无事件 ID:0 日期:11/03/2011 时间:08:00:00 用户:N/A 计算机:QA-IIS-01 描述:无法停止服务。 System.Runtime.Remoting.RemotingException: 目的 '/50e76ee1_3f40_40a1_9311_1256a0375f7d/msjxeib0oy+s0sog1mkeikjd_2.rem' 已断开或未断开 存在于服务器上。
服务器堆栈跟踪:在 System.Runtime.Remoting.Channels.ChannelServices.CheckDisconnectedOrCreateWellKnownObject(IMessage 味精)在 System.Runtime.Remoting.Channels.ChannelServices.SyncDispatchMessage(IMessage 味精)
在 [0] 处重新抛出异常:在 System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg,IMessage retMsg)在 System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(消息数据& msgData,Int32 类型)在 MyOrg.Service.IServiceHost.Stop() 在 MyOrg.Workspace.Service.MyAppService.OnStop() 在 System.ServiceProcess.ServiceBase.DeferredStop()
有关详细信息,请参阅帮助和 支持中心 http://go.microsoft.com/fwlink/events.asp.
现在出于测试目的,实际的 IServiceHost
只是将条目作为心跳和指示启动和停止的条目发布到事件日志中,而我只启动一个 AppDomain。
随着时间的推移,主服务默认应用程序域中IServiceHost
的实现者的远程代理似乎与生成域中的另一端失去了联系。
谁能解释为什么会发生这种情况,或者为默认域提供更好的方法来要求生成的域以整洁的方式关闭?
【问题讨论】:
开源项目 Topshelf 有这个功能,叫做 Shelving,它包括崩溃恢复和监控等功能。您在上面发布的服务代码看起来几乎与每个 AppDomain 的设置方式完全相同。 请阅读我关于跨AppDomain通信的博客blog.vcillusion.co.in/… 【参考方案1】:这里是黑暗中的刺。远程对象的终身租约是否到期?查看MarshalByRefObject.InitializeLifetimeService。要使对象持久化,只需覆盖并返回null
。
public override object InitializeLifetimeService()
// returning null here will prevent the lease manager
// from deleting the object.
return null;
【讨论】:
同意,默认为 10 分钟。刚好足够长,不会在调试器中捕捉到这一点。 @Hans:是的,如果我让我的调试版本运行 15 分钟然后停止服务,我会遇到我在 QA 中看到的相同错误。现在只是测试修复。 非常感谢它确实解决了这个问题。很高兴能回答 *** 问题。我以后应该问更多问题。以上是关于跨AppDomain通信问题的主要内容,如果未能解决你的问题,请参考以下文章
使用 JointCode.Shuttle 访问任意 AppDomain 的服务