Создание Singleton ChannelFactory <T> и повторное использование для клиентских подключений

В нашей среде SharePoint/ASP.NET у нас есть серия классов ретривера данных, которые все вытекают из общего интерфейса. Мне была назначена задача создания ретривера данных, который мог удаленно общаться с другими фермами SharePoint с использованием WCF. Способ, которым я его реализовал в настоящий момент, - это singleton 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

Ответ 1

Из "хорошо ли это синглтон-дизайн" хорошо, ваша реализация Singleton в порядке. Он потокобезопасен, а ChannelFactory<T> также является потокобезопасным.

Вам также не нужно беспокоиться об очистке ресурсов. Предполагая, что ChannelFactory<T> следует рекомендации Microsoft по реализации IDisposable, тогда у вас не будет проблемы с утечкой какого-то рода. Когда домен приложения будет снесен, будет создана сборка мусора, и в этот момент все будет очищено. Финализатор на ChannelFactory<T> выполнит очистку, как обычно, в вызове Dispose.

Однако, из "следует ли кэшировать точку ChannelFactory<T>", трудно сказать, потому что вы не указываете, какую версию .NET вы используете. Тем не менее, статья, на которую вы указываете, указывает, что если вы используете .NET 3.0 SP1 или выше, вам действительно не нужно это делать, вы можете создать свои прокси (при условии, что они получены из ClientBase<T>), где это необходимо в клиентский код, а не через шаблон factory, подобный этому.

Ответ 2

Пока ваш "singleton" просто возвращает вновь построенные каналы, вам не нужно беспокоиться о безопасности потоков. Вы всегда можете бросить ключевое слово volatile в статической декларации, если хотите, чтобы предотвратить любые оптимизации компилятора, которые могут подорвать вас, но я не думаю, что это необходимо в этом случае.

Просто попробуйте задать себе вопросы о долгосрочной гибкости. Например, что, если позже вы решили добавить какое-то состояние в этот метод CreateChannel? Возможно, он сделает что-то вроде создания до 10 каналов, а затем начнет повторное использование их после этого. Не могли бы вы легко изменить свой синглтон, чтобы сделать это?

Ваш ответ, вероятно, да, но что, если вы затем масштабируете вертикально на несколько серверов? Синглтона может быть недостаточно. Вам потребуется какой-то способ совместного использования состояния между экземплярами/серверами (например, база данных, распределенный кеш); что может быть трудно сделать в статическом контексте, в зависимости от того, как вы решили поделиться состоянием.

Ответ 3

I в этой статье, Даниэль Воган выступает за кеширование каналов в одном элементе управления Singleton, но никогда не кэширует ChannelFactory. Мы использовали этот подход без каких-либо проблем с успехом...

Преимущества этого:

"Когда канал переходит в состояние с ошибкой, он удаляется из кеша и воссоздается после следующего запроса..."

  • Согласование безопасности выполняется только один раз.
  • Избегает необходимости явно закрывать канал при каждом использовании.
  • Мы можем добавить дополнительные функции инициализации.
  • Мы можем выйти из строя раньше, если прокси не сможет связаться с сервером.