Как сервер WCF информирует клиента WCF об изменениях? (Лучшее решение, чем простой опрос, например, комета или длинный опрос) - PullRequest
32 голосов
/ 09 ноября 2009

см. Также " отправка WCF клиенту через брандмауэр"

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

Поскольку между клиентами и сервером может существовать межсетевой экран.

  • Все сообщения должны быть через HTTP
  • Сервер не может сделать (физический) исходящий вызов клиенту.

Поскольку я пишу и клиент, и сервер, мне не нужно ограничивать решение только использованием мыла и т. Д.


Я ищу встроенный сюрприз для " длинного опроса " / " Комета " и т. Д.


Спасибо за самый информативный ответ от Дрю Марша о том, как реализовать длинный опрос в WCF. Тем не менее, я думал, что главное «преимущество продажи» WCF заключается в том, что вы можете делать подобные вещи, просто настраивая каналы, которые будут использоваться в файле конфигурации. Например, мне нужен канал, который логически двусторонний, но только физически входящий.

Ответы [ 5 ]

49 голосов
/ 17 ноября 2009

Звучит так, будто вы уже знаете ответ: используйте длинный опрос. :) Так что, я думаю, единственное, что осталось объяснить, это то, как вы могли бы сделать это с помощью WCF и наиболее эффективным способом.


Основы:

  1. Во-первых, решите, как долго вы хотите проводить каждый «длинный опрос». Ради аргумента я собираюсь выбрать время ожидания 5 минут.
  2. На привязке на стороне клиента измените sendTimeout="00:05:00".
  3. Точно так же, как при использовании XmlHttpRequest (XHR) для длительного опроса, когда тайм-аут действительно наступает, вам необходимо его обнаружить и повторно выдать следующий запрос опроса. Это довольно просто в WCF, потому что есть конкретное исключение, TimeoutException, которое вы можете обнаружить, чтобы легко обнаружить, что это была проблема, по сравнению с некоторым другим исключением.
  4. В зависимости от того, как вы размещаете свою службу WCF, вам необходимо будет настроить себя так, чтобы обработка продолжалась до 5 минут. С точки зрения чистого WCF вам нужно убедиться, что вы установили receiveTimeout="00:05:00". Тем не менее, если вы размещаете внутри ASP.NET, вам также необходимо настроить время выполнения ASP.NET, чтобы иметь более высокое время ожидания, которое выполняется с помощью <httpRuntime executionTimeout="300" /> ( note: измерения в секундах для этого атрибута).

Быть эффективным в клиенте

Если вы просто настроите свой клиент на синхронный вызов службы и клиентские блоки в течение 5 минут в ожидании ответа, это не очень эффективно использует системные ресурсы. Вы можете поместить эти вызовы в фоновые потоки, но это все равно будет собирать ресурс потока, пока вызов не выполнен. Наиболее эффективный способ справиться с этим - использовать асинхронные операции.

Если вы создаете свои сервисные контракты вручную, я бы посоветовал проверить этот раздел на MSDN на OperationContractAttribute.AsyncPattern, чтобы узнать, как добавить пару асинхронных методов BeginXXX / EndXXX. за каждый ваш звонок. Однако, если вы используете svcutil для генерации ваших операционных контрактов, все, что вам нужно сделать, чтобы сгенерировать асинхронные методы, это передать параметр /async в командной строке. Для получения дополнительной информации по этой теме ознакомьтесь с разделом Синхронный и асинхронный в MSDN .

Теперь, когда вы определили асинхронные операции, шаблон очень похож на работу с XHR. Вы вызываете метод BeginXXX, которому передаете делегат AsyncCallback . Метод BeginXXX вернет вам IAsyncResult, который вы можете либо удержать, если хотите иметь возможность ждать операции (в более сложных сценариях), либо игнорировать, а затем инфраструктуру WCF. будет асинхронно отправлять запрос на сервер и ждать закулисного ответа. Когда получен ответ или , возникает исключение, будет вызван обратный вызов, переданный вами в метод BeginXXX. Внутри этого метода обратного вызова вам нужно вызвать соответствующий EndXXX метод, передав ему IAsyncResult, который вам передан. Во время вызова метода EndXXX вам необходимо использовать обработку исключений для обработки любых логических ошибок, которые могли произойти при вызове метода, но это также то место, где вы теперь могли бы поймать TimeoutException, который мы говорили ранее. Если вы получили хороший ответ, данные будут возвращены из вызова EndXXX, и вы сможете реагировать на эти данные любым удобным для вас способом.

ПРИМЕЧАНИЕ: Об этом шаблоне следует помнить - это характер потоков. Асинхронные обратные вызовы из WCF будут получены в потоке из пула управляемых потоков . Если вы планируете обновить пользовательский интерфейс в такой технологии, как WPF или WinForms, вам необходимо убедиться, что вы перенаправили вызовы обратно в поток пользовательского интерфейса, используя Invoke или BeginInvoke методов.

Быть эффективным на сервере

Если мы будем беспокоиться об эффективности в клиенте, мы должны быть вдвойне, когда дело доходит до сервера. Очевидно, что такой подход предъявляет повышенные требования к стороне сервера, поскольку соединение должно оставаться открытым и ожидающим до тех пор, пока не появится причина отправить уведомление клиенту. Проблема здесь в том, что вы хотите связать только среду выполнения WCF с обработкой тех клиентов, которым фактически отправляется событие. Все остальное должно просто спать, ожидая, когда произойдет событие. К счастью, тот же шаблон асинхронности, который мы только что использовали на стороне клиента, работает и на стороне сервера. Однако теперь есть существенное отличие: теперь вы должны возвращать IAsyncResult (и, следовательно, WaitHandle) из метода BeginXXX, который затем будет ожидать среда выполнения WCF. чтобы получить сигнал перед вызовом вашего EndXXX метода.

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

Помимо этого, я, честно говоря, не могу дать слишком много советов о том, как наилучшим образом реализовать асинхронную модель на стороне сервера, потому что она полностью зависит от того, из какого источника данных будут поступать ваши события. , Файловый ввод / вывод? Очередь сообщений? База данных? Какое другое проприетарное программное обеспечение со своей собственной службой обмена сообщениями, которое вы пытаетесь сделать фасадом? Я не знаю, но все они должны предлагать собственные асинхронные модели, на которых вы можете добавить свой собственный сервис, чтобы сделать его максимально эффективным.

Обновленный рецепт

Поскольку это, кажется, популярный ответ, я решил вернуться сюда и предоставить обновление, учитывая последние изменения в ландшафте. На данный момент существует библиотека .NET под названием SignalR , которая обеспечивает именно эту функциональность и, безусловно, я бы порекомендовала реализовать любую такую ​​связь с сервером.

2 голосов
/ 12 ноября 2009

Хотя это и не WCF, вы можете попробовать использовать XMPP для реализации этой функциональности. На InfoQ есть статья об этом и других системах. Хотя в статье говорится, что XMPP нельзя использовать по HTTP, вы можете использовать BOSH .

Доступны библиотеки .NET agsXMPP , чтобы назвать одну.

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

2 голосов
/ 09 ноября 2009

Если сервер может установить исходящее соединение с служебной шиной, вы можете использовать тип обратного вызова. Таким образом, клиенту / серверу вообще не нужно будет знать друг о друге, только проверяющую служебную шину. См. .NET Service Bus

Вы захотите посмотреть WSDualHttpBinding

WSDualHttpBinding обеспечивает та же поддержка протоколов веб-службы как WSHttpBinding, но для использования с дуплексные контракты. WSDualHttpBinding поддерживает только безопасность SOAP и требует надежного обмена сообщениями. это привязка требует, чтобы клиент имел публичный URI, который обеспечивает обратный вызов конечная точка для службы. Это предоставляется ClientBaseAddress. двойная привязка выставляет IP-адрес клиент к сервису. Клиент следует использовать безопасность, чтобы обеспечить его подключается только к сервисам, которым доверяет.

1 голос
/ 09 ноября 2009

Google для " WCF duplex ". Я успешно использовал это с помощью netTcpBinding (на разных континентах), но я не уверен в базовом HttpBinding.

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

0 голосов
/ 09 ноября 2009

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

...