Wcf 创建单一通道工厂<;T>;和重用客户端连接

Wcf 创建单一通道工厂<;T>;和重用客户端连接,wcf,singleton,thread-safety,channelfactory,static-constructor,Wcf,Singleton,Thread Safety,Channelfactory,Static Constructor,在我们的SharePoint/ASP.NET环境中,我们有一系列数据检索器类,这些类都派生自一个公共接口。我的任务是创建一个数据检索器,可以使用WCF与其他SharePoint场进行远程通信。目前我实现它的方式是在静态构造函数中创建一个singletonChannelFactory,然后由远程数据检索器的每个实例重用以创建一个单独的代理实例。我认为这会很好地工作,因为ChannelFactory在应用程序域中只实例化一次,并且它的创建非常简单。我的代码如下所示: public class Rem

在我们的SharePoint/ASP.NET环境中,我们有一系列数据检索器类,这些类都派生自一个公共接口。我的任务是创建一个数据检索器,可以使用WCF与其他SharePoint场进行远程通信。目前我实现它的方式是在静态构造函数中创建一个singleton
ChannelFactory
,然后由远程数据检索器的每个实例重用以创建一个单独的代理实例。我认为这会很好地工作,因为
ChannelFactory
在应用程序域中只实例化一次,并且它的创建非常简单。我的代码如下所示:

public class RemoteDataRetriever : IDataRetriever
{
    protected static readonly ChannelFactory<IRemoteDataProvider>
        RequestChannelFactory;

    protected IRemoteDataProvider _channel;

    static RemoteDataRetriever()
    {
        WSHttpBinding binding = new WSHttpBinding(
            SecurityMode.TransportWithMessageCredential, true);

        binding.Security.Transport.ClientCredentialType =
            HttpClientCredentialType.None;

        binding.Security.Message.ClientCredentialType =
            MessageCredentialType.Windows;

        RequestChannelFactory = 
            new ChannelFactory<IRemoteDataProvider>(binding);
    }

    public RemoteDataRetriever(string endpointAddress)
    {
        _channel = RemoteDataRetriever.RequestChannelFactory.
            CreateChannel(new EndpointAddress(endpointAddress));
    }
}
公共类RemoteDataRetriever:IDataRetriever
{
受保护的静态只读通道工厂
工厂;
受保护的IRemoteDataProvider\u通道;
静态RemoteDataRetriever()
{
WSHttpBinding=新的WSHttpBinding(
SecurityMode.TransportWithMessageCredential,true);
binding.Security.Transport.ClientCredentialType=
HttpClientCredentialType.None;
binding.Security.Message.ClientCredentialType=
MessageCredentialType.Windows;
RequestChannelFactory=
新工厂(装订);
}
公共RemoteDataRetriever(字符串端点地址)
{
_channel=RemoteDataRetriever.RequestChannelFactory。
CreateChannel(新端点地址(端点地址));
}
}
我的问题是,这是一个好的设计吗?我想,一旦创建了
ChannelFactory
,我就不必担心线程安全,因为我只是用它来调用
CreateChannel()
,但我错了吗?它是在改变状态还是在幕后做一些可能导致线程问题的古怪事情?此外,我是否需要将一些代码放在某个地方(静态终结器?)以手动处理
ChannelFactory
,或者我是否可以假设每当重新启动IIS时,它都会为我完成所有清理工作

相关:

只要您的“singleton”只是返回新构造的通道,您就不需要担心线程安全。如果您愿意,也可以在静态声明中抛出volatile关键字,以防止任何可能破坏您的编译器优化,但我认为在这种情况下没有必要这样做

试着问问自己关于长期灵活性的问题。例如,如果稍后您决定向这个CreateChannel方法添加一些状态,该怎么办?也许它会创建多达10个频道,然后开始重新使用它们。你能很容易地修改你的单件来做到这一点吗

您的答案可能是肯定的,但如果您随后垂直扩展到多个服务器呢?一个单身汉可能还不够。您需要某种方式在实例/服务器之间共享状态(例如,数据库、分布式缓存);在静态环境中,这可能很难做到,这取决于您决定如何共享状态。

来自“此单例设计好吗”好的,您的单例实现很好。它是线程安全的,
ChannelFactory
也是线程安全的

您也不必担心资源清理。假设
ChannelFactory
如下所示,则不会出现某种泄漏问题。当应用程序域被拆毁时,将创建一个垃圾收集,并在此时清除所有内容。
ChannelFactory
上的终结器将执行通常在调用Dispose时执行的清理

但是,从“我是否应该缓存
ChannelFactory
”的角度来看,很难说,因为您没有指明您使用的是哪个版本的.NET。但是,您所指的文章指出,如果您使用的是.NET 3.0 SP1或更高版本,您真的不需要这样做,您可以在客户端代码中需要代理的位置创建代理(假设它们来自
ClientBase
),而不是通过这样的工厂模式,Daniel Vaughan主张在Singleton manager对象中缓存通道,但从不缓存通道工厂。到目前为止,我们一直在使用这种方法,并没有任何问题

这样做的好处是:

“当通道进入故障状态时,它将从缓存中删除,并在下次请求时重新创建…”

  • 安全协商只执行一次
  • 避免每次使用时必须显式关闭通道
  • 我们可以添加额外的初始化功能
  • 如果代理无法与服务器通信,我们可以提前失败

我发现了一篇《金发女郎》的文章,它似乎表明了同样的事情-。然而,“为您生成”这个词让我对整个ClientBase方法有点反感。尽管如此,我认为你在这一点上是正确的。在对另一个WCF问题进行研究时,我发现了一个支持ChannelFactory而不是ClientBase的很好的理由-@Repo-Man:如果你愿意,但是重新包装异常不是一个最佳实践,除非你有充分的理由这样做。对于WCF中这种性质的错误,我认为它不适合重新包装异常。我知道它已经过时了。。但这难道不能有效地缓存ChannelFactory吗?因为释放工厂关闭了它的渠道。