Ответ 1
Резюме. Я считаю, что наилучшей практикой является создание экземпляра вашего клиента веб-сервиса, когда вы собираетесь его использовать, а затем пусть он выходит из сферы действия и собирает мусор. Это отражено в образцах, которые вы видите в Microsoft. Обоснование следует...
Полный. Лучшее полное описание процесса, который я нашел, находится в Как получить доступ к службе из Silverlight. Здесь пример показывает типичный шаблон создания экземпляра клиента веб-службы и позволяет ему выйти из сферы действия (без необходимости его закрытия). Клиенты веб-сервиса наследуют от ClientBase, у которого есть метод Finalize, который должен освобождать любые неуправляемые ресурсы, если это необходимо, когда объект мусор собирается.
У меня есть приличный опыт работы с веб-службами, и я использую прокси-серверы и создаю их прямо перед использованием, а затем позволяю им собирать мусор. У меня никогда не было проблемы с этим подходом. Я читал в Wenlong Dong Blog, в котором говорилось, что создание прокси было дорого, но даже он говорит, что производительность улучшилась в .NET 3.5 (возможно, с тех пор она улучшилась?). Я могу сказать вам, что производительность - относительный термин, и если ваши данные не будут получены меньше, чем тривиально, гораздо больше времени будет потрачено на сериализацию/десериализацию и транспортировку, чем на создание соединения. Это, безусловно, был мой опыт, и вам лучше оптимизировать в этих областях в первую очередь.
Наконец, поскольку я считаю, что мое мнение пока может быть недостаточным, я написал быстрый тест. Я создал веб-службу с поддержкой Silverlight, используя шаблон, предоставленный с помощью Visual Web Developer 2010 Express (с использованием метода void по умолчанию DoWork()
). Затем в моем примере Silverlight клиент я вызвал его, используя следующий код:
int counter=0;
public void Test()
{
ServiceReference1.Service1Client client = new ServiceReference1.Service1Client();
client.DoWorkCompleted += (obj, args) =>
{
counter++;
if (counter > 9999)
{
for(int j=0;j<10;j++) GC.Collect();
System.Windows.MessageBox.Show("Completed");
}
};
client.DoWorkAsync();
}
Затем я вызвал метод Test с помощью for(int i=0;i<10000;i++) Test();
и запустил приложение. Потребовалось чуть более 20 секунд, чтобы загрузить приложение и завершить вызов веб-службы (все 10000 из них). По мере того, как делались вызовы веб-служб, я видел, что использование памяти для процесса переходит на более чем 150 МБ, но как только завершенные вызовы и GC.Collect()
были названы, использование памяти упало до менее половины этой суммы. Мне кажется, что это далеко не идеальный тест, который подтверждает мне, что память не протекала, или она была незначительной (учитывая, что, как правило, нередко вызывать 10000 вызовов веб-сервисов с использованием отдельных клиентских экземпляров). Кроме того, это гораздо более простая модель, чем поддержание прокси-объекта и необходимость беспокоиться о его сбое и его повторном открытии.
Обоснование методологии тестирования: Мой тест был посвящен двум потенциальным проблемам. Одна из них - утечка памяти, а другая - время процессора, затрачиваемое на создание и уничтожение объектов. Моя рекомендация заключается в том, что безопасно следовать примерам, предоставленным компанией (Microsoft), которая поставляет эти классы. Если вас беспокоит эффективность сети, то у вас не должно быть проблем с моим примером, поскольку правильное создание/удаление этих объектов не повлияет на латентность сети. Если 99% времени тратится на сетевое время, то оптимизация для теоретического улучшения в 1%, вероятно, является расточительной с точки зрения времени разработки (при условии, что есть даже выигрыш, который, как мне кажется, мой тест ясно показывает, что мало/никто). Да, сетевые вызовы были локальными, а это означает, что в течение 10 000 вызовов службы будет потрачено всего около 20 секунд на ожидание объектов. Это составляет ~ 2 миллисекунды за вызов службы, потраченный на создание объектов. Что касается необходимости вызова Dispose, я не хотел подразумевать, что вы не должны его называть, просто потому, что это не представляется необходимым. Если вы забудете (или просто не захотите), мои тесты заставили меня поверить, что Dispose вызывается в Finalize для этих объектов. Тем не менее, вероятно, было бы более эффективно вызывать Dispose самостоятельно, но все же эффект пренебрежимо мал. Для большинства программных разработок вы получаете больше преимуществ от разработки более эффективных алгоритмов и структур данных, чем путем уклонения от таких проблем (если нет серьезной утечки памяти). Если вам нужна более эффективная работа, возможно, вам не следует использовать веб-службы, поскольку существуют более эффективные параметры транзита данных, чем система, основанная на XML.