tutorial specific signal net mvc example asp asp.net iis push-notification signalr

asp.net - specific - signalr tutorial



SignalR y límite de conexión del navegador (3)

He creado la utilidad IWC-SignalR que permite tener una única conexión SignalR para todas las ventanas (pestañas) de la misma aplicación.

Cómo funciona

Una de las ventanas se convierte en propietario de una conexión (elegida al azar) y mantiene la conexión SignalR real. Si el propietario de la conexión se cierra o se bloquea, otra ventana se convierte en propietario de la conexión, esto sucede automáticamente. La comunicación entre ventanas se realiza mediante una biblioteca de comunicaciones entre ventanas (basada en localStorage ). Esta biblioteca proporciona funcionalidad para comunicarse entre ventanas como entre procesos paralelos (bloqueos, datos compartidos, bus de eventos ...). Espero que sea de utilidad para alguien.

Hice una aplicación simple con SignalR para pruebas. Cuando la página se carga, llama a una función en el servidor, esa función llama a una función de cliente que imprime un mensaje en la pantalla. Hice eso para comprobar que tanto la función del cliente como la del servidor funcionan y que la comunicación con SignalR funciona bien.

Mi problema es que si abro la misma página en dos pestañas diferentes (lo hice en Chrome), la primera página se carga bien, pero la segunda página no llama a las funciones del servidor, SOLAMENTE si cierro la primera página.

Por lo que entiendo, es probable que haya una limitación de conexión relacionada con el navegador que no permite que SignalR se conecte más de una vez (en realidad dos, una para recibir y otra para enviar)

Actualización: encontré que nuestras otras pestañas estaban abiertas, pero ahora lo he comprobado y solo permite que 4 pestañas / páginas estén activas con las conexiones. Si trato de colocar la misma página en una nueva pestaña, no se envían datos, cuando cierro una de las otras pestañas, la nueva pestaña envía los datos de inmediato.

Lo que quería saber si hay alguna solución para eso, porque quiero que esta conectividad esté disponible si el usuario decide abrir la misma página en dos pestañas o más.

No creo que tenga nada que ver con IIS, porque por lo que sé puede aceptar miles de conexiones.


Para ampliar la respuesta de @ FreshCode, así es como implementé su idea.

Tuve la necesidad de pasar dos acciones diferentes entre pestañas. Puedo establecer notificaciones o eliminar notificaciones. Estas notificaciones son recibidas por el navegador y almacenadas como tiempos de espera que se activarán a una hora específica. La primera pestaña tiene la conexión SignalR y todas las demás no. Uno de los problemas que tuve que superar fue que el evento de "almacenamiento" se activaría independientemente de la acción que pretendía realizar (configurar / eliminar).

Lo que terminé haciendo fue pasar un objeto JSON personalizado con una propiedad que contiene la acción que quería realizar:

$(window).bind(''storage'', function () { var updateInfo = JSON.parse(localStorage.getItem(''updateInfo'')); if (updateInfo.action == ''removeNotification'') removeNotification(updateInfo.notificationId); else if (updateInfo.action == ''setNotification'') setNotification(updateInfo.notification); });

De esta manera, cada vez que configuro un elemento en el almacenamiento local, simplemente especifico la acción que debe ocurrir y solo esa acción ocurrirá en las otras pestañas. Por ejemplo, si actualizo una notificación, es una combinación de ambas acciones cuando el cliente la recibe. Elimina la notificación y establece la notificación con los valores actualizados. Así que se están realizando dos llamadas a localStorage.setItem .

function removeNotification(id) { // Check if signalR is connected. If so, I am the tab that will update // the other tabs. if ($.connection.hub.state === 1) { var updateInfo = { action: ''removeNotification'', notificationId: id }; localStorage.setItem(''updateInfo'', JSON.stringify(updateInfo)); } // brevity brevity }

Asimismo, la función setNotification .

function setNotification(notification) { if ($.connection.hub.state === 1) { var updateInfo = { action: ''setNotification'', notification: notification }; localStorage.setItem(''updateInfo'', JSON.stringify(updateInfo)); } // brevity brevity }


Este problema se solucionaría mejor con la futura especificación de Mensajería de Canal , que no ha sido implementada por ningún navegador hasta la fecha, pero logré resolverlo limitando el número de conexiones como lo describe Alex Ford y utilizando localStorage como un bus de mensajes entre pestañas.

El evento de storage permite propagar datos entre pestañas mientras mantiene abierta una sola conexión SignalR (lo que evita la saturación de la conexión). Al llamar a localStorage.setItem(''sharedKey'', sharedData) generará el evento de storage en todas las demás pestañas (no en la persona que llama):

$(window).bind(''storage'', function (e) { var sharedData = localStorage.getItem(''sharedKey''); if (sharedData !== null) console.log( ''A tab called localStorage.setItem("sharedData",''+sharedData+'')'' ); });

Puede probar if ($.connection.hub.state === 1) para determinar si una pestaña determinada debe notificar a las otras pestañas a través de localStorage (cortesía de Alex) para evitar llamadas duplicadas a localStorage.setItem .

Facebook supera esta limitación del navegador al ofrecer conexiones persistentes en varios subdominios, pero esto puede complicar la implementación y las pruebas.

Advertencias

Conexiones antiguas: en la solución de Alex, debe tener cuidado de que no se llame a Disconnect() (por ejemplo, una excepción), y debe llenar su grupo de HubConnections (o repositorio) con conexiones de hub antiguas. Si la ID de sesión no cambia (puede suceder), esto puede evitar que los nuevos clientes establezcan una conexión SignalR aunque ninguna esté activa. Alternativamente, marque las nuevas conexiones y tenga una caducidad móvil para minimizar el impacto potencial.

Bloqueo: localStorage puede estar sujeto a condiciones de carrera, ya que no implementa ningún bloqueo como se describe aquí .

Para admitir diferentes tipos de eventos, debe codificar un tipo de evento en sus mensajes JSON y probarlo en el evento de storage .

Fallbacks

Si no se puede establecer una conexión de SignalR, vuelvo a sondear el servidor cada 45 segundos para recuperar un recuento de notificaciones.

Si no quiere usar localStorage, puede usar cookies, pero no es tan limpio.