10

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

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

相关:ChannelFactory 重用策略

4

3 回答 3

3

从“这个单例设计好”的角度来看,您对单例的实现很好。它是线程安全的,ChannelFactory<T>也是线程安全的。

您也不必担心资源清理。假设ChannelFactory<T>遵循Microsoft 实施 IDisposable 的指导方针,那么您不会遇到某种泄漏的问题。当应用程序域被拆除时,将创建一个垃圾回收器,并且此时所有内容都将被清理。终结ChannelFactory<T>器将执行通常在调用 Dispose 时执行的清理操作。

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

于 2010-02-15T08:46:15.403 回答
0

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

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

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

于 2010-02-15T05:12:56.403 回答
0

在这篇文章中,Daniel Vaughan 提倡在 Singleton 管理器对象中缓存 Channel,但从不缓存 ChannelFactory。到目前为止,我们一直在使用这种方法,没有任何问题成功......

这样做的好处是:

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

  • 安全协商只执行一次。
  • 避免必须在每次使用时显式关闭通道。
  • 我们可以添加额外的初始化功能。
  • 如果代理无法与服务器通信,我们可能会提前失败。
于 2010-10-01T10:27:04.013 回答