Pregunta

Estoy creando una interfaz de usuario Silverlight 2 para un instrumento remoto. Hay dos usuarios concurrentes en diferentes sitios que interactúan con el instrumento (operador en el instrumento y científico remoto) y cualquier número de usuarios observadores que no interactúan con él, solo observando. Sin embargo, cada vez que uno de los dos usuarios activos cambia algo, estos cambios deben reflejarse inmediatamente en las IU de todos los usuarios, p. desplazar o hacer zoom en una imagen o anotar o seleccionar parte de una imagen, agregar elementos a una colección que se muestra en un cuadro de lista. Dentro del cliente utilizo colecciones observables que reflejan fácilmente los cambios realizados por ese usuario, pero es más difícil ver los cambios realizados por otro usuario. Puedo sondear los cambios de cada cliente, pero algo como las notificaciones push sería mejor. He buscado en Google muchos ejemplos, pero no he encontrado nada que sea lo que necesito. Silverlight interactúa con los servicios WCF de todo tipo, lo que significa que muchos ejemplos potenciales simplemente no funcionan. Básicamente, me he quedado sin tiempo en este proyecto y necesito ayuda rápidamente. ¿Alguien tiene alguna sugerencia de un ejemplo simple adecuado que ilustra cómo hacer esto? Soy un desarrollador experimentado pero he tenido que enseñarme a mí mismo los servicios de Silverlight y WCF y no hay nadie en mi área que sepa algo sobre estos. Aunque he realizado una buena cantidad de trabajo en ASP.NET, no soy un gurú web / Javascript. Gracias.

¿Fue útil?

Solución

La notificación push es compatible con Silverlight 2 usando el nuevo soporte WCF PollingDuplexHttpBinding. Hay dos conjuntos instalados con Silverlight SDK ( uno para la aplicación Silverlight, uno para el servidor WCF ).

Tengo un pocos blog publicaciones y una aplicación de muestra completa que demuestran cómo "enviar" actualizaciones de archivo desde un servidor de aplicaciones de consola que aloja un servicio WCF a clientes conectados. También muestra cómo cada cliente puede agregar notas a un Stock y tener esas notas sincronizadas (enviadas desde el servidor) a todos los demás clientes conectados.

La última versión del ejemplo (Parte 4) muestra cómo sincronizar las actualizaciones enviadas entre los clientes Silverlight y WPF utilizando dos puntos finales del servidor de la siguiente manera:

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();
        }
    }
}

Los clientes WPF se conectan al punto final WSDualHttpBinding y los clientes Silverlight se conectan al punto final PollingDuplexHttpBinding del mismo servicio WCF. La aplicación también muestra cómo manejar los requisitos de la política de acceso de clientes de Silverlight.

Los clientes (Silverlight o WPF) pueden agregar notas contra un Stock en su IU y estas notas se propagan de regreso al servidor para ser enviadas a todos los demás clientes. Esto demuestra la comunicación en cualquier dirección y, con suerte, realiza toda la comunicación necesaria requerida para su aplicación.

Puede ver una captura de pantalla de aplicación de demostración que se ejecuta aquí .

Otros consejos

No es que esté presionando a Flex al estilo de los fanáticos, pero de hecho, este es el tipo de arquitectura que incorporamos en todas nuestras aplicaciones basadas en Flex de manera rutinaria. Esto es lo que hacemos en Flex: sin duda, podría traducirse adecuadamente a Silverlight:

Tomamos tres ingredientes y los integramos juntos para lograr esta capacidad:

  1. Patrón de cometa (una forma compatible con HTTP para hacer notificaciones push del servidor; busque en Wikipedia para obtener más información)
  2. Temas de mensajería JMS (colas de publicación / suscriptor)
  3. El servlet Adobe BlazeDS

El último elemento implementa el patrón Comet, admite la organización de objetos AMF (formato de serialización binaria de Adobe para objetos ActionScript3) y se conecta a una cola o tema JMS. Cuando se conecta a un tema, varios clientes Flex que se ejecutan en un navegador se pueden representar como suscriptores de un tema JMS. Entonces, si algún cliente publica un mensaje (o el código del lado del servidor publica en el tema), todos los suscriptores del cliente recibirán el mensaje a través de BlazeDS y la implementación del patrón de cometa.

Efectivamente, necesita localizar o escribir un componente que logre lo que hace BlazeDS. Es posible que también deba implementar algún código de cliente que interactúe con el patrón Comet de este componente del lado del servidor.

¿WCF admite el patrón de cometa y la mensajería bidireccional? Especialmente cuando cumple con HTTP y el puerto 80 o el puerto 443 para SSL. Parece que ya has investigado eso y no has encontrado nada para la mensajería bidireccional. Por lo tanto, es posible que deba arremangarse y codificar.

Algunas cosas a tener en cuenta sobre la inserción del servidor en una aplicación web:

BlazeDS admite dos modos principales de implementación del patrón Comet (en realidad hay una tercera opción de sondeo pero la estoy ignorando):

  1. larga votación
  2. transmisión HTTP

La encuesta de larga duración que debería encontrar es más universalmente compatible con la mayoría de los navegadores web. Por lo tanto, puede simplificar simplemente apoyar eso inicialmente. O bien, puede pasar el tiempo para hacer que su código de cliente pruebe primero la transmisión HTTP y cambie a sondeo largo si es necesario.

En cuanto a un intermediario de mensajes que puede proporcionar la capacidad de publicación / suscripción, puede considerar usar ActiveMQ JMS. Es de código abierto y gratuito con soporte activo de la comunidad (también puede comprar soporte). Además, puede usar NMS para integrarse como cliente .NET.

Tener un agente de mensajes en el nivel medio es realmente importante porque será un lugar para colocar los mensajes de manera segura. Si sus clientes realizan sondeos largos, no querrá que se pierdan ningún mensaje nuevo durante un intervalo en el que no estén realmente conectados.

Otra cosa a tener en cuenta en escenarios de alto volumen de tráfico (cientos o miles de clientes, como un sitio web en Internet), debe tener un enfoque del patrón de cometa que sea escalable.

En el mundo Flex / Java, el servlet BlazeDS (que es de código abierto) se ha modificado para que funcione con el modelo asíncrono. En Java, se puede construir un escucha de socket para utilizar canales NIO y grupos de subprocesos de Java Concurrency Executor. El servidor web Tomcat tiene un escucha NIO y soporte para eventos asincrónicos de Servlet 3.0. Sin embargo, BlazeDS en particular se ha modificado para que funcione con el servidor web Jetty. La conclusión es que la escalabilidad de este enfoque asincrónico significa que un único servidor web físico puede mejorarse para admitir hasta alrededor de 20,000 conexiones de clientes de estilo Comet simultáneas.

Ha pasado un tiempo desde que hice una programación seria de .NET pero estaba acostumbrado a que las capacidades de io se parecieran mucho a Java 1.1, excepto con una capacidad de controlador de resultados asíncrono. Sin embargo, esto no es lo mismo que crear escuchas de socket asíncronos a través de canales Java NIO. Una implementación de canal NIO puede admitir cientos de miles de conexiones de socket con un grupo de subprocesos relativamente pequeño. Pero C # y .NET han pasado por t

Solo quería aclarar que PollingDuplexHttpBinding no implementa notificaciones push 'verdaderas', como revela su nombre (sondeo). Del documentación de msdn :

  

Cuando se configura con este enlace, el cliente Silverlight sondea periódicamente el servicio en la capa de red y comprueba si hay mensajes nuevos que el servicio desea enviar en el canal de devolución de llamada. El servicio pone en cola todos los mensajes enviados en el canal de devolución de llamada del cliente y los entrega al cliente cuando el cliente sondea el servicio.

Sin embargo, es más eficiente que la forma tradicional de sondear un servicio web, ya que después de cada encuesta, el servidor mantendrá el canal abierto durante un tiempo determinado (digamos 1 minuto), y si llega un mensaje en ese momento, lo hará. directamente "empujar" el mensaje al cliente. El cliente tiene que renovar repetidamente su conexión, por así decirlo, sondea el servicio.

Si desea implementar notificaciones push reales con Silverlight, creo que necesita trabajar con sockets, y le recomiendo leer algunas de las publicaciones del blog de Dan Wahlin sobre el tema.

Alternativamente,

si desea una API de Silverlight nativa sin servidores proxy, puentes o servidores web involucrados, puede usar Nirvana de my-Channels como su middleware de mensajería. Echa un vistazo a Nirvana desde my-Channels y su sitio de escaparate. (lo siento, soy un nuevo usuario y no puedo enviar enlaces):

Alex

EDITAR: en realidad está funcionando bien. Me mordió gravemente la "variable oculta" en un cierre :(

Utilicé PollingDuplex para SL2 y creo que todavía no está listo para la producción.

Mi principal problema es el hecho de que no discrimina a los clientes en la misma máquina. Si ejecuto 2 clientes, uno de ellos ya no podrá sondear el servidor y morirá por el tiempo de espera. Hay un SessionId que es diferente para los 2 clientes pero simplemente se ignora en el lado del cliente.

Del mismo modo, si elimino a un cliente y luego creo uno nuevo, el nuevo cliente recibirá las actualizaciones push del cliente anterior durante un tiempo.

¿Alguien ha encontrado los mismos problemas o están solucionados en SL3?

En realidad, ejecuté algunos códigos de demostración más y me di cuenta de que, por alguna razón, tiene que especificar InstanceContextMode e InstanceMode para que el servicio esté basado en la sesión y no en un solo punto (por lo que puedo decir). Hay problemas de rendimiento claros en el código de demostración simple que obtuve.

Es bastante desafortunado que este comportamiento no haya sido documentado.

Mi organización descubrió que la implementación de inserción de Silverlight 2.0 / WCF está un poco "no lista para el horario estelar", al menos para lo que estábamos planeando usarla.

Terminamos con XMPP / Jabber, porque es una bestia mejor formada, y puedes implementarlo con bastante facilidad en Silverlight, simplemente sacando algunos recursos de Internet.

Creo que Silverlight 3.0 implementará una implementación de inserción más nueva / mejor formada, por lo que puedo decir de la información disponible públicamente.

El PollingDuplexHttpBinding es probablemente la forma más elegante de hacerlo.

Una alternativa posiblemente menos complicada es utilizar un socket TCP desde su cliente Silverlight. Cada vez que uno de los clientes de Silverlight necesite una actualización, puede enviarle un mensaje TCP que contenga el nombre del servicio WCF al que debe llamar o alguna otra información liviana.

Utilizo este enfoque para una aplicación y funciona bien.

Una solución mucho más sencilla y poderosa en el sitio http: //www.udaparts .com / document / Tutorial / slpush.htm

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top