【问题标题】:Creating a singleton ChannelFactory<T> and reusing for client connections创建单例 ChannelFactory<T> 并重用于客户端连接
【发布时间】:2011-01-15 18:32:31
【问题描述】:

在我们的 SharePoint/ASP.NET 环境中,我们有一系列数据检索器类,它们都派生自一个通用接口。我的任务是创建一个可以使用 WCF 与其他 SharePoint 场进行远程通信的数据检索器。我目前实现它的方式是在静态构造函数中创建一个单例ChannelFactory&lt;T&gt;,然后由远程数据检索器的每个实例重用以创建一个单独的代理实例。我认为这会很好用,因为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

【问题讨论】:

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


    【解决方案1】:

    只要您的“单例”只是简单地返回新构建的通道,您就无需担心线程安全。如果您愿意,您也可以随时在静态声明中添加 volatile 关键字,以防止任何可能破坏您的编译器优化,但我认为在这种情况下没有必要。

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

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

    【讨论】:

      【解决方案2】:

      从“这个单例设计好不好”来看,您的单例实现很好。它是线程安全的,ChannelFactory&lt;T&gt; 也是线程安全的。

      您也不必担心资源清理。假设ChannelFactory&lt;T&gt; 跟在Microsoft's guidelines for implementing IDisposable 之后,那么您不会遇到某种泄漏的问题。当应用程序域被拆除时,将创建一个垃圾回收器,并且一切 都将在此时被清理。 ChannelFactory&lt;T&gt; 上的终结器将执行通常在调用 Dispose 时执行的清理操作。

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

      【讨论】:

      • 我发现了一篇金发女郎的文章,似乎表明了同样的事情 - dasblonde.net/…。然而,“为你生成”这句话让我对整个 ClientBase 方法有点反感。不过,我认为您对此表示赞同。
      • 在研究另一个 WCF 问题时,我发现了一个很好的理由来支持 ChannelFactory 而不是 ClientBase - stackoverflow.com/questions/2252747/…
      • @Repo Man:如果您愿意,但重新包装异常不是最佳做法,除非您有充分的理由这样做。对于 WCF 中这种性质的错误,我认为它不符合重新包装异常的条件。
      【解决方案3】:

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

      这样做的好处是:

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

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

      【讨论】:

      • 我知道它已经过时了..但这不会有效地缓存 ChannelFactory 吗?由于发布工厂关闭了它的频道。
      猜你喜欢
      • 1970-01-01
      • 2013-04-26
      • 2019-02-28
      • 2010-09-20
      • 2012-03-31
      • 2012-03-05
      • 1970-01-01
      • 1970-01-01
      • 2017-06-14
      相关资源
      最近更新 更多