2011-03-11 73 views
13

我一直在用C#开发Windows服务。Inter-AppDomain通信问题

一组配置文件路径在启动时被提供给该服务。对于这些文件中的每一个,该服务都会使用该文件作为ConfigurationFile启动AppDomain,并将该文件的文件夹作为ApplicationBase。每个文件夹都有一个“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中,我在停止时收到异常。在开发过程中,我们只在短时间内完成所有工作,似乎所有工作都很好。但是,在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(即时聊天 MSG)在 System.Runtime.Remoting.Channels.ChannelServices.SyncDispatchMessage(即时聊天 MSG)

异常重新抛出在[0]:在在 System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData & MSGDATA,的Int32类型)在 System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(即时聊天 reqMsg,即时聊天retMsg) MyOrg.Service.IServiceHost.Stop() at MyOrg.Workspace.Service.MyAppService.OnStop() at System.ServiceProcess.ServiceBase。DeferredStop()

欲了解更多信息,请参阅帮助和 支持中心在 http://go.microsoft.com/fwlink/events.asp

现在用于测试目的实际IServiceHost简单地将条目指示启动和停止,我只旋转了一个单一的AppDomain事件日志的心脏跳动和条目。

似乎随着时间的推移,主服务默认应用程序域中实现者IServiceHost的远程代理与生成域中的另一端失去联系。

任何人都可以解释为什么发生这种情况,或者提供一个更好的方式让默认域请求生成的域以一种整洁的方式关闭?

+0

开源项目Topshelf具有此功能,它被称为Shelving,它包括诸如崩溃恢复和监控等内容。您在上面发布的服务代码看起来几乎完全像每个AppDomain的设置方式。 – 2011-03-21 12:20:39

回答

23

在这里黑暗中刺伤。远程对象的终身租约是否过期?看看MarshalByRefObject.InitializeLifetimeService。要使对象持久化,只需重写并返回null

public override object InitializeLifetimeService() 
{ 
    // returning null here will prevent the lease manager 
    // from deleting the object. 
    return null; 
} 
+0

同意,默认10分钟。几乎就足够长的时间以至于在调试器中无法捕捉到这一点。 – 2011-03-11 17:32:11

+0

听起来很有希望@Hans:现在测试现有的代码... – AnthonyWJones 2011-03-11 17:51:07

+0

@Hans:是的,如果我让我的调试版本运行15分钟,然后停止服务我收到了我在QA中看到的同样的错误。现在只需测试修复程序。 – AnthonyWJones 2011-03-11 18:46:58