Подтвердить что ты не робот

Канал WCF и ChannelFactory Кэширование

Итак, я решил немного повысить производительность моего приложения WCF и попытаться кэшировать каналы и ChannelFactory. Есть два вопроса, которые у меня есть обо всем этом, что мне нужно прояснить, прежде чем я начну.

1) Если ChannelFactory будет реализован как одиночный?

2) Я не уверен, как кэшировать/повторно использовать отдельные каналы. Есть ли у вас примеры того, как это сделать, вы можете поделиться?

Вероятно, важно отметить, что моя служба WCF развертывается как автономное приложение с одной конечной точкой.

EDIT:

Спасибо за ответы. У меня все еще есть несколько вопросов, хотя...

1) Я думаю, я смущен относительно того, где должно происходить кэширование. Я поставляю клиентский API, который использует этот код для другого отдела нашей компании. Это кэширование происходит на клиенте?

2) API-интерфейс клиента будет использоваться как часть приложения Silverlight, это что-то изменит? В частности, какие механизмы кэширования доступны в таком сценарии?

3) Я до сих пор не совсем понимаю дизайн метода GetChannelFactory. Если у меня есть только одна служба, должен ли быть создан и кэширован только один ChannelFactory?

Я до сих пор не реализовал какую-либо функцию кеширования (потому что я совершенно не понимаю, как это должно быть сделано!), но вот что у меня для клиентского прокси:

namespace MyCompany.MyProject.Proxies
{
    static readonly ChannelFactory<IMyService> channelFactory =
        new ChannelFactory<IMyService>("IMyService");

    public Response DoSomething(Request request)
    {
        var channel = channelFactory.CreateChannel();

        try
        {
            Response response = channel.DoSomethingWithService(request);
            ((ICommunicationObject)channel).Close();
            return response;
        }
        catch(Exception exception)
        {
            ((ICommenicationObject)channel).Abort();
        }
    }
}
4b9b3361

Ответ 1

Используйте ChannelFactory для создания экземпляра factory, затем выполните кеширование этого экземпляра. Затем вы можете создавать каналы канала связи по мере необходимости/желаемые из кэшированного состояния.

У вас есть потребность в нескольких канальных фабриках (т.е. существуют ли несколько служб)? По моему опыту, там, где вы увидите наибольшее преимущество в производительности. Создание канала - довольно недорогая задача; он устанавливает все в начале, которое требует времени.

Я бы не кэшировал отдельные каналы - я бы их создал, использовал их для операции, а затем закрою. Если вы их кешируете, они могут выйти из строя, и канал будет виноват, тогда вам придется отменить его и создать в любом случае.

Не уверен, почему вы хотите использовать singleton для реализации ChannelFactory, особенно если вы собираетесь его создавать и кэшировать, и там только одна конечная точка.

Я отправлю код примера позже, когда у меня будет немного больше времени.

UPDATE: примеры кода

Вот пример того, как я реализовал это для проекта на работе. Я использовал ChannelFactory<T>, так как приложение, которое я разрабатывал, представляет собой n-уровневое приложение с несколькими службами, и будет добавлено больше. Цель состояла в том, чтобы иметь простой способ создать клиента один раз в жизни приложения, а затем создать каналы связи по мере необходимости. Основы идеи не мои (я получил это из статьи в Интернете), хотя я модифицировал реализацию для своих нужд.

У меня есть статический вспомогательный класс в моем приложении, и внутри этого класса у меня есть словарь и метод для создания каналов связи из канала factory.

Словарь выглядит следующим образом (объект - это значение, поскольку оно будет содержать разные фабрики каналов, по одному для каждой службы). Я помещаю "Cache" в примере как своего рода заполнитель - замените синтаксис любым используемым механизмом кэширования.

public static Dictionary<string, object> OpenChannels
{
    get
    {
        if (Cache["OpenChannels"] == null)
        {
            Cache["OpenChannels"] = new Dictionary<string, object>();
        }

        return (Dictionary<string, object>)Cache["OpenChannels"];
    }
    set
    {
        Cache["OpenChannels"] = value;
    }
}

Далее приведен метод создания канала связи из экземпляра factory. Метод проверяет, существует ли factory первый, если нет, он создает его, помещает его в словарь и затем генерирует канал. В противном случае он просто генерирует канал из кэшированного экземпляра factory.

public static T GetFactoryChannel<T>(string address)
{

    string key = typeof(T.Name);

    if (!OpenChannels.ContainsKey(key))
    {
        ChannelFactory<T> factory = new ChannelFactory<T>();
        factory.Endpoint.Address = new EndpointAddress(new System.Uri(address));
        factory.Endpoint.Binding = new BasicHttpBinding();
        OpenChannels.Add(key, factory);
    }

    T channel = ((ChannelFactory<T>)OpenChannels[key]).CreateChannel();

    ((IClientChannel)channel).Open();

    return channel;
}

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

Наконец, когда я использую его в приложении, я обычно создаю канал, делаю свой бизнес и закрываю его (или, если это необходимо, прервать его). Например:

IMyServiceContract client;

try
{
    client = Helper.GetFactoryChannel<IMyServiceContract>("http://myserviceaddress");

    client.DoSomething();

    // This is another helper method that will safely close the channel, 
    // handling any exceptions that may occurr trying to close.
    // Shouldn't be any, but it doesn't hurt.
    Helper.CloseChannel(client);
}
catch (Exception ex)
{
    // Something went wrong; need to abort the channel
    // I also do logging of some sort here
    Helper.AbortChannel(client);
}

Надеемся, что приведенные выше примеры дадут вам кое-что, чтобы продолжить. Я использую что-то подобное этому около года в производственной среде, и он работал очень хорошо. 99% всех проблем, с которыми мы столкнулись, обычно связаны с чем-то вне приложения (внешними клиентами или источниками данных, которые не находятся под нашим прямым контролем).

Сообщите мне, если что-то неясно или у вас есть дополнительные вопросы.

Ответ 2

Вы всегда можете сделать свой ChannelFactory статичным для каждого контракта WCF...

Вы должны знать, что из .Net 3.5 объекты прокси объединяются по соображениям производительности по каналу factory. Вызов метода ICommunicationObject.Close() фактически возвращает объект в пул в надежде, что он может быть повторно использован.

Я бы посмотрел на профилировщик, если вы хотите сделать некоторую оптимизацию, если вы можете предотвратить только один вызов ввода-вывода в коде, он может значительно перевесить любую оптимизацию, которую вы будете делать с каналом factory. Не выбирайте область для оптимизации, используйте профилировщик, чтобы найти, где можно настроить оптимизацию. Например, если у вас есть база данных SQL, вы, вероятно, найдете в своих запросах некоторые плохие плотные плоды, которые принесут вам заказы на увеличение производительности, если они еще не были оптимизированы.

Ответ 3

Создание канала так дорого стоит. на самом деле WCF уже имеет механизм кэширования для ChannelFactory, если вы используете ClientBase на клиенте, а не в чистом ChannelFactory. Но кеш будет истек, если вы сделаете некоторые операции (пожалуйста, сообщите нам об этом, если хотите). Для проблемы с ErOx у меня появилось другое решение, и я думаю, что это лучше. см. ниже:


namespace ChannelFactoryCacheDemo
{
    public static class ChannelFactoryInitiator
    {
        private static Hashtable channelFactories = new Hashtable();

        public static ChannelFactory Initiate(string endpointName)
        {
            ChannelFactory channelFactory = null;

            if (channelFactories.ContainsKey(endpointName))//already cached, get from the table
            {
                channelFactory = channelFactories[endpointName] as ChannelFactory;
            }
            else // not cached, create and cache then
            {
                channelFactory = new ChannelFactory(endpointName);
                lock (channelFactories.SyncRoot)
                {
                    channelFactories[endpointName] = channelFactory;
                }
            }
            return channelFactory;
        }
    }
    class AppWhereUseTheChannel
    {
        static void Main(string[] args)
        {
            ChannelFactory channelFactory = ChannelFactoryInitiator.Initiate("MyEndpoint");
        }
    }

    interface IMyContract { }
}

вы можете самостоятельно настроить логику и параметры метода Initiate, если у вас есть другое требование. но этот класс инициатора не ограничивается только одной конечной точкой. он является мощным для всей конечной точки в вашем приложении. с надеждой. это хорошо работает для вас. КСТАТИ. это решение не от меня. Я получил это из книги.