Silverlight и push-уведомления

Я создаю пользовательский интерфейс Silverlight 2 для удаленного прибора. На разных площадках взаимодействуют два одновременно работающих пользователя (оператор на приборе и удаленный ученый) и любое количество пользователей-наблюдателей, не взаимодействующих с ним, просто наблюдающих. Однако всякий раз, когда один из двух активных пользователей изменяет что-либо, эти изменения должны немедленно отражаться в пользовательском интерфейсе всех пользователей, например, панорамирование или масштабирование изображения, аннотирование или выбор части изображения, добавление элементов в коллекцию, отображаемую в списке. В клиенте я использую наблюдаемые коллекции, которые легко отражают изменения, сделанные этим пользователем, но труднее видеть изменения, сделанные другим пользователем. Я могу опросить изменения от каждого клиента, но что-то вроде push-уведомлений было бы лучше. Я много гуглил по примерам, но не нашел ничего, что мне нужно. При взаимодействии Silverlight со службами WCF возникают всевозможные проблемы безопасности, что означает, что многие потенциальные примеры просто не работают. У меня практически не осталось времени на этот проект, и мне нужна срочная помощь. У кого-нибудь есть предложение подходящего простого примера, который иллюстрирует, как это сделать? Я опытный разработчик, но мне приходилось учить себя службам Silverlight и WCF, и никто в моей области не знает ничего об этом. Даже несмотря на то, что я проделал немалую работу над ASP.NET, я не гуру веб /Javascript. Благодарю.

8 ответов

Решение

Push-уведомление поддерживается в Silverlight 2 с использованием новой поддержки WCF PollingDuplexHttpBinding. Вместе с Silverlight SDK установлено две сборки ( одна для приложения Silverlight, другая для сервера WCF).

У меня есть несколько постов в блоге и полный пример приложения, в котором показано, как "выталкивать" обновления Stock с сервера консольных приложений, который самостоятельно размещает службу WCF для подключенных клиентов. В нем также показано, как каждый клиент может добавлять заметки к акции и синхронизировать эти заметки (отправленные с сервера) со всеми другими подключенными клиентами.

В последней версии образца (часть 4) показано, как синхронизировать отправленные обновления между клиентами Silverlight и WPF с использованием двух конечных точек сервера следующим образом:

using System;
using System.ServiceModel;
using System.ServiceModel.Description;

namespace StockServer
{
    public class StockServiceHost : ServiceHost
    {
        public StockServiceHost(object singletonInstance, params Uri[] baseAddresses)
            : base(singletonInstance, baseAddresses)
        {
        }

        public StockServiceHost(Type serviceType, params Uri[] baseAddresses)
            : base(serviceType, baseAddresses)
        {
        }

        protected override void InitializeRuntime()
        {
            this.AddServiceEndpoint(
                typeof(IPolicyProvider),
                new WebHttpBinding(),
                new Uri("http://localhost:10201/")).Behaviors.Add(new WebHttpBehavior());

            this.AddServiceEndpoint(
                typeof(IStockService),
                new PollingDuplexHttpBinding(),
                new Uri("http://localhost:10201/SilverlightStockService"));

            this.AddServiceEndpoint(
                typeof(IStockService),
                new WSDualHttpBinding(WSDualHttpSecurityMode.None),
                new Uri("http://localhost:10201/WpfStockService"));

            base.InitializeRuntime();
        }
    }
}

Клиенты WPF подключаются к конечной точке WSDualHttpBinding, а клиенты Silverlight подключаются к конечной точке PollingDuplexHttpBinding той же службы WCF. В приложении также показано, как обрабатывать требования политики доступа клиента Silverlight.

Клиенты (Silverlight или WPF) могут добавлять заметки к акциям в своем пользовательском интерфейсе, и эти заметки распространяются обратно на сервер для отправки всем остальным клиентам. Это демонстрирует связь в любом направлении и, мы надеемся, выполняет все необходимые коммуникации для вашего приложения.

Вы можете увидеть скриншот демо-приложения, запущенного здесь.

Не то, чтобы я толкаю Flex по-фанатски, но на самом деле это та архитектура, которую мы регулярно внедряем во все наши приложения на базе Flex. Вот что мы делаем на Flex- без сомнения, его можно было бы соответствующим образом перевести на Silverlight:

Мы используем три компонента и объединяем их вместе, чтобы реализовать эту возможность:

  1. Шаблон кометы (HTTP-совместимый способ делать push-уведомления сервера - для получения дополнительной информации обратитесь к Википедии)
  2. Разделы обмена сообщениями JMS (очереди публикации / подписки)
  3. Сервлет Adobe BlazeDS

Последний элемент реализует шаблон Comet, поддерживает маршалинг объектов AMF (двоичный формат сериализации Adobe для объектов ActionScript3) и соединяется с очередью или темой JMS. При соединении с темой несколько клиентов Flex, работающих в браузере, могут быть проксированы как подписчики на тему JMS. Поэтому, если какой-либо клиент публикует сообщение (или серверный код публикуется в теме), всем подписчикам клиента будет отправлено сообщение через BlazeDS и реализацию Comet Pattern.

По сути, вам нужно найти или написать компонент, который выполняет то, что делает BlazeDS. Вам также может понадобиться реализовать некоторый клиентский код, который взаимодействует с шаблоном Comet этого серверного компонента.

Поддерживает ли WCF шаблон Comet и двунаправленный обмен сообщениями? Особенно там, где соответствует HTTP и порт 80 или порт 443 для SSL. Похоже, вы уже изучили это и не нашли ничего для двунаправленного обмена сообщениями. Так что вам, возможно, придется закатать рукава и заняться кодированием.

Некоторые вещи, которые нужно отметить, когда вы отправляете сервер в веб-приложение:

BlazeDS поддерживает два основных режима реализации шаблона Comet (на самом деле есть третий вариант опроса, но я его игнорирую):

  1. давно опрос
  2. HTTP поток

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

Что касается брокера сообщений, который может обеспечить возможность публикации / приостановки, вы можете рассмотреть возможность использования ActiveMQ JMS. Это с открытым исходным кодом и бесплатно с активной поддержкой сообщества (вы также можете купить поддержку). Кроме того, вы можете использовать NMS для интеграции в качестве клиента.NET.

Наличие посредника сообщений, находящегося на среднем уровне, на самом деле важно, потому что это будет место для безопасного размещения сообщений. Если ваши клиенты выполняют длинные опросы, вы бы не хотели, чтобы они пропускали какие-либо новые сообщения в течение интервала, когда они на самом деле не подключены.

Еще одна вещь, которую следует учитывать в сценариях с большим объемом трафика (сотни или тысячи клиентов, таких как веб-сайт в Интернете), необходимо иметь подход к масштабируемому шаблону кометы.

В мире Flex/Java сервлет BlazeDS (с открытым исходным кодом) был модифицирован для работы с асинхронной моделью. В Java слушатель сокета может быть построен для использования каналов NIO и пулов потоков Java Concurrency Executor. На веб-сервере Tomcat есть прослушиватель NIO и поддержка асинхронных событий Servlet 3.0. В частности, BlazeDS был модифицирован для работы с веб-сервером Jetty. Суть в том, что масштабируемость этого асинхронного подхода означает, что отдельный физический веб-сервер может быть расширен для поддержки примерно до 20000 одновременных клиентских соединений в стиле Comet.

Я давно занимался серьезным программированием на.NET, но привык к тому, что возможности io были во многом похожи на Java 1.1, за исключением возможности асинхронного обработчика результатов. Это, однако, не то же самое, что создание асинхронных слушателей сокетов через каналы Java NIO. Реализация канала NIO может поддерживать от сотен до тысяч соединений сокетов с относительно небольшим пулом потоков. Но C# и.NET прошли через два или три значительных оборота, возможно, были добавлены новые возможности ввода-вывода, сравнимые с каналами NIO.

Я просто хотел уточнить, что PollingDuplexHttpBinding не реализует "истинные" push-уведомления, как показывает его имя (опрос). Из документации MSDN:

При настройке с этой привязкой клиент Silverlight периодически опрашивает службу на сетевом уровне и проверяет наличие новых сообщений, которые служба хочет отправить по каналу обратного вызова. Служба ставит в очередь все сообщения, отправленные по каналу обратного вызова клиента, и доставляет их клиенту, когда клиент опрашивает службу.

Однако он более эффективен, чем традиционный способ опроса веб-службы, поскольку после каждого опроса сервер будет сохранять канал открытым в течение определенного времени (скажем, 1 минуты), а если сообщение поступит в это время, он будет напрямую сообщение клиенту. Клиент должен многократно возобновить соединение, так сказать, опрашивает сервис.

Если вы хотите реализовать настоящие push-уведомления с помощью silverlight, я считаю, что вам нужно работать с сокетами, и я рекомендую прочитать некоторые посты Дэна Уолина в блоге на эту тему.

С другой стороны,

если вам нужен собственный Silverlight API без прокси, мостов или веб-серверов, вы можете использовать Nirvana из my-Channels в качестве промежуточного программного обеспечения для обмена сообщениями. Проверьте Нирвану от моих каналов и их демонстрационный сайт. (извините, я новый пользователь и не могу отправить ссылки):

Alex

РЕДАКТИРОВАТЬ: это на самом деле работает нормально. Я был сильно укушен "скрытой переменной" в закрытии:(

Я использовал PollingDuplex для SL2 и думаю, что он еще не готов к производству.

Моя главная проблема заключается в том, что он не различает клиентов на одном компьютере. Если я запустлю 2 клиента, то один из них не сможет больше опрашивать сервер и умрет по истечении времени ожидания. Существует SessionId, который отличается для 2 клиентов, но он просто игнорируется на стороне клиента.

Аналогичным образом, если я убью клиента, а затем создам нового, новый клиент какое-то время получит push-обновления от предыдущего клиента.

Кто-нибудь сталкивался с такими же проблемами или они исправлены в SL3?

На самом деле я запустил еще несколько демонстрационных кодов и понял, что по какой-то причине вы должны указать InstanceContextMode и InstanceMode, чтобы служба основывалась на сеансах, а не на одиночном (насколько я могу судить). В простом демонстрационном коде, который я вытащил, есть явные проблемы с производительностью.

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

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

В итоге мы выбрали XMPP/Jabber, потому что это более хорошо сформированный зверь, и вы можете довольно легко реализовать его в Silverlight, просто вытащив некоторые ресурсы из Интернета.

Я действительно полагаю, что Silverlight 3.0 будет реализовывать более новую / более правильно сформированную реализацию push, исходя из того, что я могу сказать из общедоступной информации.

PollingDuplexHttpBinding, вероятно, самый элегантный способ сделать это.

Еще одна менее сложная альтернатива - использовать TCP-сокет от вашего клиента Silverlight. Когда одному из клиентов Silverlight необходимо отправить обновление, вы можете отправить ему TCP-сообщение, содержащее имя службы WCF, которую он должен вызвать, или какую-то другую легковесную информацию.

Я использую этот подход для приложения, и он работает хорошо.

Одно гораздо более простое и мощное решение на сайте http://www.udaparts.com/document/Tutorial/slpush.htm

Другие вопросы по тегам