Как освобождать ресурсы в WCF?
От: baranovda Российская Империя  
Дата: 15.06.08 18:53
Оценка:
и нужно ли это делать вообще?
Я создаю клиентов динамически при помощи ChannelFactory, примерно так:

Сервис
[ServiceContract]
public interface ICalculator
{
    [OperationContract]
    int Add(int a, int b);
}


Клиент
ChannelFactory<ICalculator> factory = new ChannelFactory<ICalculator>(binding, url);
ICalculator calculator = factory.CreateChannel();


Вопрос: нужно ли принудительно закрывать канал через вызов метода ChannelFactory.Close() после того, как мне этот канал больше не нужен? Останутся ли висеть на сервере объекты, реализующие интерфейс ICalculator, если я канал не закрою или они автоматически соберутся сборщиком мусора?
Re: Как освобождать ресурсы в WCF?
От: Аноним  
Дата: 15.06.08 19:17
Оценка:
Здравствуйте, baranovda, Вы писали:

B>Вопрос: нужно ли принудительно закрывать канал через вызов метода ChannelFactory.Close() после того, как мне этот канал больше не нужен? Останутся ли висеть на сервере объекты, реализующие интерфейс ICalculator, если я канал не закрою или они автоматически соберутся сборщиком мусора?

Есть народная примета: если тип реализует IDisposable, то лучше вызвать Dispose по окончанию работы с объектом или использовать using.
Можно не закрывать и сборщик когда-нибудь соберет, но лучше закрыть, т.к. сэкономите ресурсы сервера.
Re[2]: Как освобождать ресурсы в WCF?
От: baranovda Российская Империя  
Дата: 15.06.08 19:39
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Здравствуйте, baranovda, Вы писали:


B>>Вопрос: нужно ли принудительно закрывать канал через вызов метода ChannelFactory.Close() после того, как мне этот канал больше не нужен? Останутся ли висеть на сервере объекты, реализующие интерфейс ICalculator, если я канал не закрою или они автоматически соберутся сборщиком мусора?

А>Есть народная примета: если тип реализует IDisposable, то лучше вызвать Dispose по окончанию работы с объектом или использовать using.
А>Можно не закрывать и сборщик когда-нибудь соберет, но лучше закрыть, т.к. сэкономите ресурсы сервера.

С IDisposable в WCF отдельная песня. Реализация ChannelFactory этот интерфейс реализует, но СКРЫВАЕТ. Это вычислил некто Dan Rigsby — здесь. Зачем это сделали авторы WCF — непонятно. Поэтому завернуть использование этого объекта в using можно, но как бы нежелательно.

Товарищи из Microsoft в качестве workaround предлагают ВЕЗДЕ использовать такую конструкцию (из той же статьи) и пространно мотивируют свое архитектурное решение здесь
ChannelFactory<IMyService> channelFactory = null;
try
{
    channelFactory =
        new ChannelFactory<IMyService>();
    channelFactory.Open();

    // Do work…

    channelFactory.Close();
}
catch (CommunicationException)
{
    if (channelFactory != null)
    {
        channelFactory.Abort();
    }
}
catch (TimeoutException)
{
    if (channelFactory != null)
    {
        channelFactory.Abort();
    }
}
catch (Exception)
{
    if (channelFactory != null)
    {
        channelFactory.Abort();
    }
    throw;
}



Я погонял тесты с и без закрытия каналов, попрофайлил IIS — все нормально, память не отжирается. Количество одновременных конкурентных подключений ограничивается исключительно значением параметра конфигурации maxConcurrentCalls и никак не зависит от того, закрываю ли я канал явно или просто его бросаю.

Ничего не понятно.
Re: Как освобождать ресурсы в WCF?
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 15.06.08 20:17
Оценка:
Здравствуйте, baranovda, Вы писали:

B>Вопрос: нужно ли принудительно закрывать канал через вызов метода ChannelFactory.Close() после того, как мне этот канал больше не нужен?


Нужно. А лучше сделать клиентский интерфейс, который наследуется от IDisposable и использовать using.

B> Останутся ли висеть на сервере объекты, реализующие интерфейс ICalculator, если я канал не закрою или они автоматически соберутся сборщиком мусора?


В итоге соберутся, но не сразу. Простого ответа на этот вопрос нет — там много чего задействуется, а есть еще и reliable messaging.
... <<RSDN@Home 1.2.0 alpha 4 rev. 1090 on Windows Vista 6.0.6001.65536>>
AVK Blog
Re[2]: Как освобождать ресурсы в WCF?
От: baranovda Российская Империя  
Дата: 15.06.08 20:23
Оценка:
Здравствуйте, AndrewVK, Вы писали:

AVK>Здравствуйте, baranovda, Вы писали:


B>>Вопрос: нужно ли принудительно закрывать канал через вызов метода ChannelFactory.Close() после того, как мне этот канал больше не нужен?


AVK>Нужно. А лучше сделать клиентский интерфейс, который наследуется от IDisposable и использовать using.


Отнаследовать ICalculator от IDisposable или создать обёртку над ChannelFactory, реализующую IDisposable?
Re[3]: Как освобождать ресурсы в WCF?
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 15.06.08 20:25
Оценка:
Здравствуйте, baranovda, Вы писали:

B>Отнаследовать ICalculator от IDisposable или создать обёртку над ChannelFactory, реализующую IDisposable?


Отнаследовать ICalculator от IDisposable и от IClientChannel.
... <<RSDN@Home 1.2.0 alpha 4 rev. 1090 on Windows Vista 6.0.6001.65536>>
AVK Blog
Re[4]: Как освобождать ресурсы в WCF?
От: baranovda Российская Империя  
Дата: 15.06.08 20:35
Оценка:
Здравствуйте, AndrewVK, Вы писали:

AVK>Здравствуйте, baranovda, Вы писали:


B>>Отнаследовать ICalculator от IDisposable или создать обёртку над ChannelFactory, реализующую IDisposable?


AVK>Отнаследовать ICalculator от IDisposable и от IClientChannel.


Угу. Пытался. В этом случае происходит вот что:


ICalculator GetInterface(url)
{
    ICalculator result = new ChannelFactory<ICalculator>(binding, url).CreateChannel();
    return result;
}

void Test()
{
   using (ICalculator calc = GetInterface("http://localhost/ICalculator.svc"))
   {
      int ret = calc.Add(1, 2);
   }
}


Здесь: если реализация метода Add выкидывает исключение на сервере, то при попытке неявного вызова метода calc.Dispose() финалайзером секции using вываливается другое исключение, что-то типа "не могу вызывать метод Dispose удалённого объекта, поскольку канал находится в состоянии Fault". В принципе, логично.
Re[5]: Как освобождать ресурсы в WCF?
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 15.06.08 20:37
Оценка:
Здравствуйте, baranovda, Вы писали:

B>Здесь: если реализация метода Add выкидывает исключение на сервере, то при попытке неявного вызова метода calc.Dispose() финалайзером секции using вываливается другое исключение, что-то типа "не могу вызывать метод Dispose удалённого объекта, поскольку канал находится в состоянии Fault". В принципе, логично.


Так обрабатывать то надо исключения.
... <<RSDN@Home 1.2.0 alpha 4 rev. 1090 on Windows Vista 6.0.6001.65536>>
AVK Blog
Re[6]: Как освобождать ресурсы в WCF?
От: baranovda Российская Империя  
Дата: 15.06.08 20:47
Оценка:
Здравствуйте, AndrewVK, Вы писали:

AVK>Здравствуйте, baranovda, Вы писали:


AVK>Так обрабатывать то надо исключения.


А вот не хочу Хочу, чтобы исключения всегда пробрасывались с сервера клиенту, а системные ресурсы, если клиент не обработал fault, освобождались самостоятельно.
Re[7]: Как освобождать ресурсы в WCF?
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 15.06.08 20:49
Оценка:
Здравствуйте, baranovda, Вы писали:

B> Хочу, чтобы исключения всегда пробрасывались с сервера клиенту


В WCF это невозможно — контракты сбоев надо явно описывать, а потом отделять FaultException на клиентской стороне и обрабатывать его отдельно. Так уж дизайн WCF построен.
... <<RSDN@Home 1.2.0 alpha 4 rev. 1090 on Windows Vista 6.0.6001.65536>>
AVK Blog
Re[8]: Как освобождать ресурсы в WCF?
От: baranovda Российская Империя  
Дата: 15.06.08 21:00
Оценка:
Здравствуйте, AndrewVK, Вы писали:

AVK>Здравствуйте, baranovda, Вы писали:


B>> Хочу, чтобы исключения всегда пробрасывались с сервера клиенту


AVK>В WCF это невозможно — контракты сбоев надо явно описывать, а потом отделять FaultException на клиентской стороне и обрабатывать его отдельно. Так уж дизайн WCF построен.


Насколько я знаю, для того, чтобы не мучаться с сериализацией исключений и передачей их клиенту, можно использовать атрибут [ServiceBehavior(IncludeExceptionDetailInFaults = true)] или, что то же самое, настроить соответствующим образом Behavior в серверном конфигурационном файле. Серверные исключения в этом случае будут преобразованы в строку и переданы клиенту как FaultException<String>. Мне большего и не надо. Меня класс исключения вообще не волнует Но почистить за собой хочу в любом случае
Re[3]: Как освобождать ресурсы в WCF?
От: IB Австрия http://rsdn.ru
Дата: 15.06.08 21:22
Оценка: 1 (1)
Здравствуйте, baranovda, Вы писали:

B>Я погонял тесты с и без закрытия каналов, попрофайлил IIS — все нормально, память не отжирается.

Зато отжираются соединения с сервером.

B> Количество одновременных конкурентных подключений ограничивается исключительно значением параметра конфигурации maxConcurrentCalls и никак не зависит от того, закрываю ли я канал явно или просто его бросаю.

Это только если у тебя стратегия PerCall стоит.

B>Ничего не понятно.

Там все просто. IClientChannel.Close — закрывает конкретное соединение с сервером, ChannelFactory.Close закрывает все соединения в этой фабрике. Если клиент многопоточный, то не закрывая соединение можно очень быстро словить TimeoutException: The open operation did not complete within the allotted timeout of 00:01:00. The time allotted to this operation may have been a portion of a longer timeout.
Мы уже победили, просто это еще не так заметно...
Re[3]: Как освобождать ресурсы в WCF?
От: pt4h Беларусь http://dzmitryhuba.blogspot.com/
Дата: 15.06.08 21:23
Оценка:
Здравствуйте, baranovda, Вы писали:


B>Я погонял тесты с и без закрытия каналов, попрофайлил IIS — все нормально, память не отжирается. Количество одновременных конкурентных подключений ограничивается исключительно значением параметра конфигурации maxConcurrentCalls и никак не зависит от того, закрываю ли я канал явно или просто его бросаю.

Вы управляете ресурсами клиента в данном случае и никак не серверными. Сервер сам отвечает за время жизни своих ресурсов. Закрытие канала просто дпомогает быстрее понять серверу, что ресурсы уже можно освободить. Если вы этого не сделаете, то со временем он все равно поймет, что он больше не используется и освободит.
Re[9]: Как освобождать ресурсы в WCF?
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 16.06.08 10:35
Оценка:
Здравствуйте, baranovda, Вы писали:

B>Серверные исключения в этом случае будут преобразованы в строку и переданы клиенту как FaultException<String>. Мне большего и не надо. Меня класс исключения вообще не волнует


Ну если очень тебе приспичило — делай как знаешь. Только не жалуйся тогда, что неудобно.
... << RSDN@Home 1.2.0 alpha 4 rev. 1089>>
AVK Blog
Re: Как освобождать ресурсы в WCF?
От: baranovda Российская Империя  
Дата: 18.06.08 08:00
Оценка:
Здравствуйте, baranovda, Вы писали:

B>и нужно ли это делать вообще?

B>Я создаю клиентов динамически при помощи ChannelFactory, примерно так:

B>Вопрос: нужно ли принудительно закрывать канал через вызов метода ChannelFactory.Close() после того, как мне этот канал больше не нужен? Останутся ли висеть на сервере объекты, реализующие интерфейс ICalculator, если я канал не закрою или они автоматически соберутся сборщиком мусора?



В общем, резюмирую.

// Сервер
[ServiceContract]
public interface ICalculator
{
    [OperationContract]
    int Add(int a, int b);
}


// Клиент
ChannelFactory<ICalculator> factory = new ChannelFactory<ICalculator>(binding, url);
ICalculator calculator = factory.CreateChannel();


В этом коде происходит вот что: при обращении к методу ChannelFactory.CreateChannel() фабрика в действительности возвращает ссылку на Transparent proxy, который (это очевидно) можно привести к интерфейсу ICalculator и (внимание!) интерфейсу IChannel, хотя эта возможность не документирована в MSDN и я её выдрал рефлектором. Таким образом, наследовать ICalculator от IDisposable не нужно, а для того, чтобы гарантированно закрыть канал, необходимо выполнить следующее приведение:

ChannelFactory<ICalculator> factory = new ChannelFactory<ICalculator>(binding, url);
ICalculator calculator = factory.CreateChannel();
ICnannel channel = calculator as IChannel;

int i = calculator.Add(1, 2);

if (channel != null)
    channel.Close();
Re[9]: Как освобождать ресурсы в WCF?
От: EM Великобритания  
Дата: 18.06.08 12:31
Оценка:
Здравствуйте, baranovda, Вы писали:

B>Здравствуйте, AndrewVK, Вы писали:


AVK>>Здравствуйте, baranovda, Вы писали:


B>>> Хочу, чтобы исключения всегда пробрасывались с сервера клиенту


AVK>>В WCF это невозможно — контракты сбоев надо явно описывать, а потом отделять FaultException на клиентской стороне и обрабатывать его отдельно. Так уж дизайн WCF построен.


B>Насколько я знаю, для того, чтобы не мучаться с сериализацией исключений и передачей их клиенту, можно использовать атрибут [ServiceBehavior(IncludeExceptionDetailInFaults = true)] или, что то же самое, настроить соответствующим образом Behavior в серверном конфигурационном файле. Серверные исключения в этом случае будут преобразованы в строку и переданы клиенту как FaultException<String>. Мне большего и не надо. Меня класс исключения вообще не волнует Но почистить за собой хочу в любом случае


Так похендленое исключение канал переводит в Faulted state для некоторых биндингов. Соответственно, клиентский код приведенный выше по ветке будет падать на выходе из using-a
Опыт — это такая вещь, которая появляется сразу после того, как была нужна...
Re[2]: Как освобождать ресурсы в WCF?
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 18.06.08 22:23
Оценка:
Здравствуйте, baranovda, Вы писали:

B>Таким образом, наследовать ICalculator от IDisposable не нужно, а для того, чтобы гарантированно закрыть канал, необходимо выполнить следующее приведение:


Наследовать нужно, чтобы руками ничего не приводить. А про IClientChannel я тебе с самогно начала писал, но он не позволяет использовать using. Кстати, в релизе или SP1 IClientChannel уже отнаследован от IDisposable, так что одного его достаточно.
... <<RSDN@Home 1.2.0 alpha 4 rev. 1090 on Windows Vista 6.0.6001.65536>>
AVK Blog
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.