gpt4 book ai didi

multithreading - 具有后台线程的WCF NetTCP

转载 作者:行者123 更新时间:2023-12-03 09:00:48 25 4
gpt4 key购买 nike

背景:

我有一个在带有NetTCP绑定(bind)的Windows服务中托管WCF服务的系统。要将新服务添加到集合中,您只需在 services/>中添加标准WCF配置条目,然后在自定义配置部分中添加一行,告诉主机框架它需要初始化服务。每个服务都使用其自己的后台线程和AppDomain实例进行初始化,以保持所有隔离。

这是服务如何初始化的示例:

Host
- ServerManager
- ServiceManager
- BaseServerHost

ServerManager实例具有ServiceManager的集合,每个ServiceManager都与单个服务实例相关联,这是标准WCF实现所在的位置(ServiceHost.Open/Close等)。 ServiceManager实例通过使用BaseServerHost基类(抽象)实例化(基于配置-它具有标准的程序集/类型定义)服务的实例。每个服务都必须继承自此,框架才能使用它。 作为初始化过程的一部分,BaseServerHost公开几个事件,特别是拥有ServiceManager自身附加到的UnhandledException事件。 (这部分与下面的问题有关。)

整个过程对我们来说异常有效(一个实例正在运行63个服务),因为我可以找一个对WCF一无所知的人,他们可以很快地创建服务。

题:

我遇到的问题是后台线程。在标准的插入/更新/删除方法调用(例如,向其他系统发送消息)之后,端点上大多数公开的方法都会进行大量 Activity 。为了保持性能(前端是基于Web的),我们让初始的insert/update/delete方法完成其工作,然后触发后台线程来处理最终用户不需要等待的所有内容去完成。该选项非常有用,直到未处理该后台线程中的某些内容并导致整个Windows服务崩溃为止,据我所知,这是设计使然(我可以)。

根据我的所有研究,我发现无法实现全局try/catch(减去使用启用1.1处理背景崩溃的黑客配置),因此我的团队将不得不回过头来将它们放在适当的位置。除此之外,我发现在WCF托管的端点方面似乎在每个调用中都位于其自己的线程中,而让该线程与“父级”对话一直是一场噩梦。从服务的 Angular 来看,这是布局:
Endpoint (svc - inherits from BaseServerHost, mentioned above)
- Business Layer
- Data Layer

当我在业务层的后台线程上捕获异常时,我将其冒泡到Endpoint实例(该实例继承自BaseServerHost),然后该实例针对该特定服务(由实例化的拥有的ServiceManager附加到该实例)触发BaseServerHost的UnhandledException事件。它)。不幸的是,事件处理程序不再存在,因此它什么也不做。我已经尝试了很多方法来使它起作用,到目前为止,我所有的努力都是徒劳的。

在查看完整模型时(如下所示),我需要使业务层了解其父端点(此方法有效),并且端点需要了解正在运行的BaseServerHost实例,而该实例需要了解托管它的ServiceManager,因此错误可以冒出来,用于我们的标准日志记录过程。
Host
- ServerManager
- ServiceManager <=====================
- BaseServerHost ||
- Endpoint (svc) ||
- Business Layer <======
- Data Layer

我曾经尝试过静态类,但是运气不佳,甚至使ServerManager成为静态并扩展了其先前内部的ServiceManager集合(以便可以将其关闭),但是该集合也总是为空或为null。

关于这项工作的想法?

编辑:在进一步深入研究之后,我找到了一个确切说明如何实现此工作的示例。在标准ASP.NET网站中的任何页面/处理程序等上,都可以使用HttpContext.Current属性访问该请求的当前上下文。这正是我希望此方法与“ServiceManager.Current”一起工作,返回该服务拥有的ServiceManager的方式。也许有帮助吗?

最佳答案

也许您应该考虑使用CallContext做一些事情:

http://msdn.microsoft.com/en-us/library/system.runtime.remoting.messaging.callcontext.aspx

您可以使用SetData/GetData或LogicalSetData/LogicalGetData,具体取决于您是想将ServiceManager与一个物理线程(SetData)还是与“逻辑”线程(LogicalSetData)关联。使用LogicalSetData,您可以在一个线程以及该线程的“子”线程中提供相同的ServiceManager实例。当我找到它们时,将尝试发布一些可能有用的链接。

这是codeproject上"Virtual Singleton Pattern"的链接。

这是"Thread Singleton"的链接

这是"Ambient Context"的链接

所有这些想法都是相似的。本质上,您的对象具有静态的Current属性(可以获取或获取/设置)。 Current使用SetData(将“Current”值与当前线程关联)或LogicalSetData(将“Current”值与当前线程关联并将该值传递到任何值)将其值放入CallContext(并从CallContext中获取) “子”线程)。

HttpContext以类似的方式实现。

System.Diagnostics.CorrelationManager是另一个以类似方式实现的好例子。

我认为“环境上下文”文章很好地解释了您可以用此想法完成的工作。

每当我对CallContext表示反对时,我都会尝试也包含此entry from Jeffrey Richter's blog.的链接

最终,我不确定这是否会帮助您。如果您有一个多线程服务器应用程序(也许每个请求由一个线程执行,并且多个请求可以同时在不同的线程上完成),那将很有用,每个线程可能有一个ServiceManager。在这种情况下,您可能在ServiceManager上有一个静态Current方法,该方法将始终为特定线程返回正确的ServiceManager实例,因为该方法将ServiceManager存储在CallContext中。像这样:

public class ServiceManager
{
static string serviceManagerSlot = "ServiceManager";

public static ServiceManager Current
{
get
{
ServiceManager sm = null;
object o = CallContext.GetData(serviceManagerSlot);
if (o == null)
{
o = new ServiceManager();
CallContext.SetData(serviceManagerSlot, o);
}
sm = (ServiceManager)o;
return sm;
}

set
{
CallContext.SetData(serviceManagerSlot, value);
}
}
}

在过程的早期,您可以配置ServiceManager以在当前线程(或当前“逻辑”线程)中使用,然后存储在“Current”属性中:
ServiceManager sm = new ServiceManager(thread specific properties?);
ServiceManager.Current = sm;

现在,无论何时在代码中检索ServiceManager.Current,它都将是当前正在其中执行的线程的正确ServiceManager。

这整个想法可能并不是您真正想要的。

从您的评论中可以说,如果发生异常,您尝试检索的CallContext数据为null。这可能意味着在与设置Call​​Context数据所在的线程不同的线程上引发和/或捕获了异常。您可以尝试使用LogicalSetData来查看是否有帮助。

正如我说的,我不知道这对您有什么帮助,但是希望我已经足够清楚(示例也已经足够清楚),以便您可以判断这些想法是否适用于您的情况。

祝好运。

关于multithreading - 具有后台线程的WCF NetTCP,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4925622/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com