Звучит так, будто вы уже знаете ответ: используйте длинный опрос. :) Так что, я думаю, единственное, что осталось объяснить, это то, как вы могли бы сделать это с помощью WCF и наиболее эффективным способом.
Основы:
- Во-первых, решите, как долго вы хотите проводить каждый «длинный опрос». Ради аргумента я собираюсь выбрать время ожидания 5 минут.
- На привязке на стороне клиента измените
sendTimeout="00:05:00"
.
- Точно так же, как при использовании XmlHttpRequest (XHR) для длительного опроса, когда тайм-аут действительно наступает, вам необходимо его обнаружить и повторно выдать следующий запрос опроса. Это довольно просто в WCF, потому что есть конкретное исключение,
TimeoutException
, которое вы можете обнаружить, чтобы легко обнаружить, что это была проблема, по сравнению с некоторым другим исключением.
- В зависимости от того, как вы размещаете свою службу 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 , которая обеспечивает именно эту функциональность и, безусловно, я бы порекомендовала реализовать любую такую связь с сервером.