WCF ChannelFactory и кэширование каналов в клиентском приложении ASP.NET

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

Зная, что каждый сервисный запрос, сделанный разными пользователями, должен использовать другой канал, я думаю, что кэширую Channel per-request (HttpContext.Current.Items) и кеширую ChannelFactory, используемый для создания канала для каждого приложения (HttpApplication.Items), поскольку я могу создать более одного канала с тем же ChannelFactory.

Однако у меня есть вопрос относительно этого механизма кеширования, когда дело доходит до закрытия ChannelFactory и Channel.

  1. Нужно ли мне закрывать канал после его использования, в конце запроса, или можно оставить его там, чтобы он был закрыт (?), Когда контекст этого запроса умирает?
  2. А как насчет ChannelFactory? Поскольку каждый канал связан с ChannelFactory, который его создал, безопасно ли сохранять тот же ChannelFactory в течение всего процесса приложения (AppDomain)?

Вот код, который я использую для этого:

public class ServiceFactory
{
    private static Dictionary<string, object> ListOfOpenedChannels
    {
        get
        {
            if (null == HttpContext.Current.Items[HttpContext.Current.Session.SessionID + "_ListOfOpenedChannels"])
            {
                HttpContext.Current.Items[HttpContext.Current.Session.SessionID + "_ListOfOpenedChannels"] = new Dictionary<string, object>();
            }

            return (Dictionary<string, object>)HttpContext.Current.Items[HttpContext.Current.Session.SessionID + "_ListOfOpenedChannels"];
        }
        set
        {
            HttpContext.Current.Items[HttpContext.Current.Session.SessionID + "_ListOfOpenedChannels"] = value;
        }
    }

    public static T CreateServiceChannel<T>()
    {
        string key = typeof(T).Name;

        if (ListOfOpenedChannels.ContainsKey(key))
        {
            return (T)ListOfOpenedChannels[key];
        }
        else
        {
            ChannelFactory<T> channelF = new ChannelFactory<T>("IUsuarioService");
            T channel = channelF.CreateChannel();
            ListOfOpenedChannels.Add(key, channel);
            return channel;
        }
    }
}

Спасибо!


person tucaz    schedule 01.12.2009    source источник


Ответы (2)


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

Да, фабрика каналов (дорогостоящая часть) может оставаться в течение всего срока службы приложения.


Обновлять

Начиная с .Net 4.5 есть встроенные параметры кэширования для фабрик ChannelFactory Caching .NET 4.5

person MattC    schedule 01.12.2009
comment
+1 точно - кешируйте дорогую часть - ChannelFactory - но создавайте каналы по мере необходимости и закрывайте / удаляйте как можно раньше - person marc_s; 01.12.2009
comment
Отличные ребята, поэтому, если я сохраню в кэше всего ОДНУ фабрику каналов в течение всего срока службы приложения и буду использовать ее повторно при создании всех каналов, у меня не будет проблем, не так ли? - person tucaz; 01.12.2009
comment
Один завод каналов для каждого типа обслуживания, правильно. Таким образом, вам не нужно выполнять все отражение и создание типа при каждом вызове, поэтому для повышения производительности вам не следует использовать прокси, сгенерированный VS, поскольку класс gens использует новую фабрику при каждом вызове. - person MattC; 01.12.2009
comment
вам не следует использовать прокси, сгенерированный VS, поскольку класс gens использует новую фабрику при каждом вызове - согласно ссылке в конце эта конкретная проблема была решена с помощью .NET 3.5, так что ChannelFactory кэшируется в ClientBase. blogs.msdn.com/wenlong/archive/2007/10/27/ - person Xiaofu; 13.03.2010
comment
@Xiaofu: Это правда, что ClientBase<T> в некоторых случаях будет использовать кеш MRU на ChannelFactory<T>. Он не будет кэшировать ChannelFactoy, если Endpoint или ClientCredentials будут изменены или если Binding определен программно. Есть способ принудительно кэшировать ChannelFactory, установив для CacheSettings значение CacheSettings.AlwaysOn. msdn.microsoft.com/en-us/library /hh314046(v=vs.110).aspx - person Derek W; 16.08.2014

Это в сторону. Почему вы используете SessionID в качестве контекстного ключа? Context.Items уникален для каждого запроса. Это:

HttpContext.Current.Items[HttpContext.Current.Session.SessionID +"_ListOfOpenedChannels"]

должен быть функционально эквивалентен:

HttpContext.Current.Items["ListOfOpenedChannels"]
person Frank    schedule 03.03.2010
comment
Я понял это после того, как разместил этот вопрос. Окончательный результат здесь: github.com/tucaz/CommunicationsManager Спасибо - person tucaz; 04.03.2010