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

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

Ответ 1

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

У меня есть несколько сообщений в блогах и полное примерное приложение, которые демонстрируют, как "нажимать" обновления запасов с сервера консоли, размещает службу 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) могут добавлять примечания к фонду в своем пользовательском интерфейсе, и эти заметки распространяются обратно на сервер, которые будут перенаправлены всем другим клиентам. Это демонстрирует связь в любом направлении и, надеюсь, выполняет всю необходимую коммуникацию, необходимую для вашего приложения.

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

Ответ 2

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

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

  • Кометный шаблон (способ, совместимый с HTTP, чтобы делать уведомления о push-сервере) - см. Википедию для получения дополнительной информации)
  • Темы сообщений JMS (очереди публикаций/подписчиков)
  • Сервлет Adobe BlazeDS

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

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

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

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

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

  • давно опрос
  • Потоковая передача HTTP

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

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

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

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

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

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

Ответ 3

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

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

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

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

Ответ 4

В качестве альтернативы,

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

Алекс

Ответ 5

EDIT: он работает нормально. Я был сильно укушен "скрытой переменной" в закрытии: (

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

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

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

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

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

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

Ответ 6

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

Мы закончили работу с XMPP/Jabber, потому что это более образованный зверь, и вы можете легко реализовать его в Silverlight, просто получая некоторые ресурсы из Интернета.

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

Ответ 7

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

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

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