创建单个ChannelFactory <t>并重用客户端连接</t>

时间:2010-02-11 15:28:57

标签: wcf singleton thread-safety channelfactory static-constructor

在我们的SharePoint / ASP.NET环境中,我们有一系列数据检索器类,这些类都来自通用接口。我被分配了创建数据检索器的任务,该数据检索器可以使用WCF与其他SharePoint场远程通信。我现在实现它的方式是在静态构造函数中创建单例ChannelFactory<T>,然后由远程数据检索器的每个实例重用以创建单独的代理实例。我认为这样可以正常运行,因为ChannelFactory只能在应用程序域中实例化一次,并且其创建为guaranteed to be thread-safe。我的代码看起来像这样:

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

我的问题是,这是一个好设计吗?我认为一旦ChannelFactory被创建,我不需要担心线程安全,因为我只是用它来调用CreateChannel()但是我错了?它是在改变状态还是在幕后做一些可能导致线程问题的时髦的东西?另外,我是否需要在某个地方放置一些代码(静态终结器?)来手动处理ChannelFactory,或者我可以假设每当IIS重新启动它时,它会为我做所有的清理工作吗?

相关:ChannelFactory Reuse Strategies

3 个答案:

答案 0 :(得分:3)

从“这单身设计好”这个单身人士的实现就可以了。它是线程安全的,ChannelFactory<T>也是线程安全的。

您也不必担心资源清理。假设ChannelFactory<T>Microsoft's guidelines for implementing IDisposable之后,那么你就不会遇到某种泄漏的问题。当应用程序域被拆除时,将创建垃圾收集,并且此时将清除所有ChannelFactory<T>上的终结器将执行通常在调用Dispose时执行的清理。

但是,从“我应该缓存ChannelFactory<T>”的角度来看,很难说,因为你没有说明你所使用的.NET版本。但是,您指出的文章表明,如果您使用的是.NET 3.0 SP1或更高版本,您实际上不需要这样做,您可以创建代理(假设它们来自ClientBase<T>)您需要它的地方在客户端代码中,而不是通过像这样的工厂模式。

答案 1 :(得分:0)

只要您的“单身人士”只是简单地返回新构建的频道,您就不必担心线程安全。如果你愿意的话,你总是可以在静态声明上抛出volatile关键字,以防止任何可能破坏你的编译器优化,但我不认为在这种情况下是必要的。

试着问自己有关长期灵活性的问题。例如,如果您稍后决定在此CreateChannel方法中添加一些状态,该怎么办?也许它会像创建多达10个频道一样,然后在此之后开始重新使用它们。你能轻易修改你的单身人士吗?

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

答案 2 :(得分:0)

I this article,Daniel Vaughan主张在Singleton管理器对象中缓存Channels,但从不缓存ChannelFactory。到目前为止,我们一直在使用这种方法没有成功...

这样做的好处是:

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

  • 安全协商只执行一次。
  • 避免在每次使用时明确关闭频道。
  • 我们可以添加其他初始化功能。
  • 如果代理无法与服务器通信,我们可能会提早失败。