背景:
我有一个在带有 NetTCP 绑定的 Windows 服务中托管 WCF 服务的系统。要将新服务添加到集合中,您只需在 <system.serviceModel -> services /> 中添加标准 WCF 配置条目,然后在自定义配置部分中添加一行,告诉宿主框架它需要初始化服务。每个服务都使用自己的后台线程和 AppDomain 实例进行初始化,以保持一切隔离。
以下是如何初始化服务的示例:
Host
- ServerManager
- ServiceManager
- BaseServerHost
ServerManager 实例有一个 ServiceManager 的集合,每个 ServiceManager 与一个服务实例相关联,这是标准 WCF 实现所在的位置(ServiceHost.Open/Close 等)。ServiceManager 实例通过使用 BaseServerHost 基类(抽象)实例化(基于配置 - 它具有标准程序集/类型定义)服务的实例。每个服务都必须从这里继承,以便框架能够使用它。作为初始化过程的一部分,BaseServerHost 公开了几个事件,特别是拥有的 ServiceManager 附加到的 UnhandledException 事件。(这部分对于下面的问题至关重要。)
整个过程对我们来说非常有效(一个实例运行 63 个服务),因为我可以带一个对 WCF 一无所知的人,他们可以非常快速地创建服务。
问题:
我遇到的问题是后台线程。我们端点上的大多数公开方法在标准插入/更新/删除方法调用(例如向其他系统发送消息)之后执行大量活动。为了保持性能(前端是基于网络的),我们让初始的插入/更新/删除方法完成它的工作,然后启动一个后台线程来处理最终用户不需要等待的所有东西去完成。此选项非常有效,直到该后台线程中的某些内容未处理并导致整个 Windows 服务关闭,我理解这是设计使然(我可以接受)。
根据我的所有研究,我发现没有办法实现全局 try/catch(减去使用启用 1.1 处理后台崩溃的黑客配置),因此我的团队将不得不返回并在适当的地方获取这些. 除此之外,我发现 WCF 托管的端点端似乎在每次调用时都在其自己的线程中,并且让该线程与“父级”对话一直是一场噩梦。从服务的角度来看,这里是布局:
Endpoint (svc - inherits from BaseServerHost, mentioned above)
- Business Layer
- Data Layer
当我在业务层的后台线程上捕获异常时,我将其冒泡到 Endpoint 实例(继承自 BaseServerHost),然后尝试为该特定服务触发 BaseServerHost 的 UnhandledException 事件(由实例化的拥有的 ServiceManager 附加它)。不幸的是,事件处理程序不再存在,所以它什么都不做。我已经尝试了很多事情来让它发挥作用,到目前为止,我所有的努力都是徒劳的。
查看完整模型时(如下所示),我需要让业务层了解其父端点(这可行),并且端点需要了解正在运行的 BaseServerHost 实例,该实例需要了解托管它的 ServiceManager 所以在我们的标准日志记录程序中,可以将错误冒泡到此。
Host
- ServerManager
- ServiceManager <=====================
- BaseServerHost ||
- Endpoint (svc) ||
- Business Layer <======
- Data Layer
我尝试了静态类但没有运气,甚至将 ServerManager 设为静态并公开其先前的内部 ServiceManager 集合(因此它们可以被关闭),但该集合也始终为空或 null。
对制作这项工作的想法?
编辑:在进一步挖掘之后,我找到了一个关于我如何设想这个工作的例子。在标准的 ASP.NET 网站中,在任何页面/处理程序等上,您都可以使用 HttpContext.Current 属性来访问该请求的当前上下文。这正是我希望它与返回该服务的拥有 ServiceManager 的“ServiceManager.Current”一起使用的方式。也许这有帮助?