AppDomain 间通信问题

发布于 2024-10-21 08:02:15 字数 3377 浏览 2 评论 0原文

我一直在用 C# 开发 Windows 服务。

该服务启动时会提供一组配置文件路径。对于每个文件,服务将使用该文件作为其 ConfigurationFile 并使用该文件的文件夹作为 ApplicationBase 来启动一个 AppDomain。每个文件夹都会有一个设置为 PrivateBinPath 的“bin”文件夹。

这些文件夹中的“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 日期:2011年3月11日 时间: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] 处重新抛出异常:at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg、IMessage retMsg) at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& 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 实现者的远程代理似乎已经与生成的域中的另一端失去了联系。

任何人都可以解释为什么会发生这种情况,或者为默认域提供更好的方法来要求生成的域以整齐的方式关闭?

I've been developing a Windows Service in C#.

A set of configuration file paths is supplied to this service when it starts. For each of these files the service will spin up an AppDomain using the file as its ConfigurationFile and the folder of this file as the ApplicationBase. Each folder will have a "bin" folder that is set as PrivateBinPath.

The "bin" folder in these folders contain a small assembly that is shared in common with the service, this assembly contains the interface IServiceHost. Also the type name and assembly name of a class that implements the IServiceHost interface is known.

The whole CreateServiceHost method looks like this:-

    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;
    }

The IServiceHost interface is incredibly complex:-

public interface IServiceHost
{
    void Start();
    void Stop();
}

The service OnStart contains something like this:-

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();
    }
}

The OnStop is equally straight-forward (for now to keep things simple the IServiceHost.Stop are blocking calls).

protected override void OnStop()
{
    foreach (IServiceHost host in serviceHosts)
    {
        host.Stop();
    }
}

This all simple enough and it works fine when testing on development machines. However in QA I'm getting exceptions when it is stopped. When in development we spin things up only for a short period it all seems to work fine. However in QA the service is only stopped every 24 hours. In this case it consistently fails to stop correctly.

Here is an example of what ends up in the Event log:-

Event Type: Error Event
Source: Workspace Services Event
Category: None Event ID: 0
Date: 11/03/2011 Time: 08:00:00
User: N/A Computer: QA-IIS-01
Description: Failed to stop service.
System.Runtime.Remoting.RemotingException:
Object
'/50e76ee1_3f40_40a1_9311_1256a0375f7d/msjxeib0oy+s0sog1mkeikjd_2.rem'
has been disconnected or does not
exist at the server.

Server stack trace: at
System.Runtime.Remoting.Channels.ChannelServices.CheckDisconnectedOrCreateWellKnownObject(IMessage
msg) at
System.Runtime.Remoting.Channels.ChannelServices.SyncDispatchMessage(IMessage
msg)

Exception rethrown at [0]: at
System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage
reqMsg, IMessage retMsg) at
System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData&
msgData, Int32 type) at
MyOrg.Service.IServiceHost.Stop()
at
MyOrg.Workspace.Service.MyAppService.OnStop()
at
System.ServiceProcess.ServiceBase.DeferredStop()

For more information, see Help and
Support Center at
http://go.microsoft.com/fwlink/events.asp.

Now for test purposes the actual IServiceHost simply posts entries to the event log as a heart beat and entries indicating start up and stop and I'm only spinning up a single AppDomain.

It would seem that over time the remote proxy for the implementer of IServiceHost in the main service default app domain has lost touch with its other end in the generated domain.

Can anyone explain why that is happening, or offer a better way for the default domain to ask the generated domains to shutdown in a tidy manner?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

山色无中 2024-10-28 08:02:15

这里是黑暗中的一刀。远程对象的生命周期租约是否到期?查看 MarshalByRefObject.InitializeLifetimeService。要使对象持久化,只需覆盖并返回null

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

A stab in the dark here. Is the lifetime lease on the remote object expiring? Look into MarshalByRefObject.InitializeLifetimeService. To make the object persistent, just override and return null.

public override object InitializeLifetimeService()
{
    // returning null here will prevent the lease manager
    // from deleting the object.
    return null;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文