Buscar contenidos

martes, 26 de junio de 2018

Implementando SignalR en ASP.NET MVC

https://diegobersano.com.ar/2016/04/19/implementando-signalr-en-asp-net-mvc/

https://www.variablenotfound.com/search/label/signalr

Ejemplo única session

Código en el cliente

@section Scripts {
    <script src="ABC.net/Scripts/jquery.signalR-2.2.0.min.js"></script>
    <script src="ABC.net/signalr/hubs"></script>
    <script>
        $(function () {

           var notification = $.connection.notificationHub;

            //Logout-----------------------------------------------
            notification.client.logout = function (userLogin) {
                alert("Se cerrará la sesión del usuario : [" + userLogin + "] porque hay más de una sesión abierta!");
                window.location.href = "/Home/Logout"
            };

            //Logged-----------------------------------------------
            notification.client.logged = function (userLogin) {
                alert("Usuario [" + userLogin + "] Logeado con éxito");
            };

            //Login------------------------------------------------
            $.connection.hub.start().done(function () {
                $("#submit").click(function () {

                    var username = $("#username").val();
                    var password = $("#password").val();

                    if ((username == "minion" && password == "123") || (username == "pitufo" && password == "123")) {
                        notification.server.registrarLogin(username);
                    } else {
                        alert("Usuario y/o Contraseña incorrectos!");
                    }

                });
            });

            //Inicia Conexión--------------------------------------
            $.connection.hub.starting(function () {
                console.log('Conexión iniciada..');
            });

            //Finaliza Conexion-----------------------------------
            $.connection.hub.disconnected(function () {
                console.log('Conexión finalizada..');
            });
           
        });

    </script>

}


  1. Internet, asynchrony, multiuser… wow!
  2. HTTP: you are the client, and you are the boss
  3. Introducing SignalR
    Estos tres primeros capítulos introducen las aplicaciones asíncronas en tiempo real y los conceptos básicos que necesitamos conocer para trabajar con SignalR: qué es, qué nos aporta, y qué mecanismos hacen que todo esto funcione.
  4. Persistent connections En el cuarto capítulo comenzamos ya a trabajar con conexiones persistentes, tanto en el lado servidor como en el cliente, describiendo en detalle las APIs que ofrece SignalR para comunicar ambos extremos.
  5. Hubs Aquí se describe profundidad el uso de hubs, tanto en el lado cliente como en el servidor, describiendo detalladamente las herramientas disponibles para enviar y recibir datos desde ambas partes, mantener el estado, implementar trazas, y muchos otros aspectos de interés al programar hubs de SignalR.
  6. Persistent connections and hubs from other threads
    En este capítulo se describen las herramientas proporcionadas por SignalR para utilizar hubs y conexiones persistentes desde hilos de ejecución externos a dicho framework.
  7. Real-time multiplatform applications
    Este capítulo está dedicado a la publicación y consumo de servicios desde servidores y clientes no web. Se describen técnicas de self-hosting en distintos entornos, y cómo implementar clientes en plataformas como Windows 8 o Windows Phone.
  8. Deploying and scaling SignalR
    En este capítulo se muestran los fundamentos de la escalabilidad de SignalR y distintas estrategias para enfrentarse a los problemas asociados al escalado de servicios. Estudiamos los backplanes incluidos de serie en el producto e incluso cómo crear backplanes propios, y finalmente, apuntamos técnicas para mejorar el rendimiento y medir el rendimiento de nuestros sistemas.
  9. Advanced topics
    Aquí tratamos temas como autorización en Hubs, extensión de SignalR, inyección de dependencias, pruebas unitarias, intercepción de mensajes e integración con otros frameworks en cliente y servidor

Implementando SignalR en ASP.NET MVC


En la entrada anterior vimos algunos puntos asociados al funcionamiento general de SignalRy el planteo que propone. Lo que veremos en este nuevo post es cómo implementarlo en una aplicación ASP.NET MVC y lograr al menos una interacción básica.
Lo primero que haremos es definir el funcionamiento de nuestra aplicación. Lo que queremos lograr es armar un check-list compartido entre distintos usuarios, donde cuando uno de ellos marque un elemento como realizado o no, a los otros también les aparezca dicho estado actualizado. Para este ejemplo haremos algo muy básico, lo cual con el correr de los post’s de esta serie iremos haciendo crecer.
Comenzaremos con una aplicación ASP.NET MVC básica, instalando el paquete Nugetasociado a SignalR:
Install-Package Microsoft.AspNet.SignalR
Una vez finalizada la instalación, deberemos crear el archivo Startup.cs dentro de la raíz de nuestro proyecto web. Es en el mismo donde mediante OWIN estableceremos la inicialización de los mapeos necesarios para la interacción con SignalR, quedando el archivo de la siguiente forma:

ImplementacionSignalR - ClaseStartup
Definición de clase Startup usando OWIN

Hasta allí está lo que es la configuración inicial del proyecto. Lo posterior a hacer será crear el Hub que se encargará de la comunicación con los clientes. Para ello crearemos la carpeta Hubs dentro de la raíz del proyecto web, y dentro de la misma el elemento “SignalR Hub Class” con nombre NotificationHub:

ImplementacionSignalR - AgregarHub
Creación de la clase de tipo Hub

Nota: Como consideración, en general se define el nombre de forma de que termine con el posfijo “Hub“.
Una vez finalizada la creación tendremos nuestro Hub de la siguiente forma:

ImplementacionSignalR - HubOriginal
Hub creado por defecto

Como se puede apreciar nuestra clase hereda de Hub, que es la clase base de SignalR que tiene el comportamiento base. A su vez también tenemos el método de ejemplo Hello, el cual nos da un ejemplo mínimo de funcionamiento. Será en esta clase donde tendremos definidos todos los métodos del servidor que los distintos clientes pueden invocar, con sus parámetros. Como mencionamos en el post anterior, podremos usar tanto objetos simples como complejos.
Luego en la implementación de cada método estará lo que necesitemos hacer como reacción a lo que nos ha indicado el cliente, pudiendo no hacer nada o comunicarse con algún cliente particular para indicarle una acción o información. En el método de ejemplo al crear la clase – Hello – lo que está haciendo es indicarle a todos los clientes que ejecuten la función hellodefinida en el contexto del cliente. Ese funcionamiento es algo que todavía no hemos visto, ya llegaremos en breve a ese punto.
Lo siguiente que haremos será modificar esta clase para que tenga el comportamiento que nosotros estamos deseando, obteniendo el siguiente resultado:

ImplementacionSignalR - HubModificado
Hub modificado con nuesta lógica de aplicación

  1. Definimos el método Notificate, el cual recibe como parámetros el identificador de la tarea y un booleano indicando su resultado.
  2. En la implementación de dicho método no tendremos lógica adicional, indicándoles directamente a todos los clientes que ejecuten la función markDone con la información recibida en los parámetros.
Así de simple es la lógica desde el lado del servidor. Veamos que hay que hacer para la ejecución del lado del cliente.
Para este ejemplo crearemos la vista /Home/Notification, donde agregaremos el siguiente código que simula nuestras tareas a marcar cómo resueltas o no:
ImplementacionSignalR - DesarrolloHtml
Básicamente tenemos un listado de inputs de tipo checkbox, con un atributo para poder referenciarlos y saber cuál es el seleccionado (podríamos haber usado el atributo id, pero soy partidario de separar el propósito de uso de cada atributo).
Ahora en lo que debemos trabajar es en la lógica del lado del cliente, es decir en el código JavaScript que se encargará de enviar la información al servidor y dejar disponibles los métodos necesarios para que el servidor los pueda invocar. En nuestro ejemplo nos quedará de la siguiente forma:

ImplementacionSignalR - DesarrolloScripts
Código JavaScript asociado a SignalR

Hay mucho que aclarar sobre esto, veámoslo en detalle:
  1. Incluimos la referencia a los scripts de SignalR, los cuales se agregaron al instalar el paquete Nuget como una de sus dependencias.
  2. Esta referencia es fija siempre, y contiene el código autogenerado de cada uno de los Hub’s que tengamos en nuestra aplicación, con sus métodos. Esto es el resultado de la configuración realizada en la clase Startup anteriormente.
  3. Referenciamos al Hub, utilizando el nombre definido en la clase pero en el estilo lower camel case.
  4. Sobre la referencia de nuestro Hub tendremos el objeto client, donde iremos agregando todos los métodos que nuestros clientes expongan para ser invocados por el servidor. Como se puede ver, tendremos el método que establecimos invocar desde nuestro Hub con los parámetros necesarios y su implementación.
  5. Realizamos la inicialización del Hub. A su vez, en el evento “done” del mismo estableceremos la lógica para invocar al servidor.
  6. Similar a lo establecido en el punto 4, tendremos el objeto server, donde podremos ir invocando a los métodos expuestos (nuevamente usando lower camel case).
  7. Pasamos los parámetros definidos en el método correspondiente del Hub.
Y con esto ya tenemos todo listo para hacer la primer prueba de ejecución. Obviamente que para validar el funcionamiento vamos a tener que contar con más de un cliente, lo cual en esta prueba haremos con dos navegadores trabajando en paralelo.

ImplementacionSignalR - Resultado
Ejecución de la aplicación

Excelente, ya logramos el objetivo inicial!! 🙂
Ahora indaguemos un poco en lo que es el aspecto de comunicación entre el servidor y los clientes. En la entrada anterior vimos los mecanismos disponibles para esta interacción, estableciendo una “jerarquía de elección” para lograr la técnica de conexión más óptima pero sin perder funcionalidad. Para ello agregaremos la siguiente línea dentro de nuestro script JS:
$.connection.hub.logging = true;
Con la misma establecemos que en la consola de los clientes se vaya registrando la información asociada a la conexión, entre ellas el mecanismo utilizado. Para lograr una contraposición en las técnicas vamos a probar con Chrome e IE 8 (emulado), con las cuales esperamos una diferencia significativa.

ImplementacionSignalR - ConexionesNavegadores
Resultado de la determinación de la técnica adecuada para cada navegador

Como se puede apreciar, en Chrome se está usando WebSockets como era de esperar. En cambio en IE 8 al no haber soporte se usa HTTP Long Polling. Lo que nos queda validar es el comportamiento que se logra a nivel usuario con esta combinación de técnicas, lo cual se puede ver a continuación:

ImplementacionSignalR - ResultadoIE8
Ejecución de la aplicación en IE 8

Y efectivamente todo sigue funcionando de forma correcta, incluso con un navegador de generación anterior como IE 8. Como se puede ver en la pestaña de red de IE 8 están los sucesivos request’s que quedan pendientes hasta que el servidor tiene algo que notificar, mientras que en el caso de Chrome no vemos ninguna interacción, ya que va todo por la conexión WebSockets establecida inicialmente.
Otra cosa que es interesante es lo que mencionábamos en el punto 2 del código JavaScriptde nuestros clientes:
Esta referencia es fija siempre, y contiene el código autogenerado de cada uno de los Hub’s que tengamos en nuestra aplicación, con sus métodos…
Así que indaguemos un poco en la misma, la cual efectivamente encontraremos sobre la ruta~/signalr/hubs. Entre varias porciones de código genéricas del funcionamiento, lo que encontraremos es la definición del Hub que tenemos creado en el servidor, con las firmas de los métodos correspondientes:

ImplementacionSignalR - HubAutogeneradoCliente
Código autogenerado con la definición del Hub


Conclusiones

Como pudimos apreciar en este post, SignalR realmente logra lo que habíamos mencionado en la entrada anterior. De forma realmente rápida hemos logrado establecer una funcionalidad en tiempo real sin problemas. Detengámonos tan solo unos minutos a pensar todo lo que deberíamos hacer para lograr hacer funcionar este ejemplo sin SignalR, por trivial que sea su funcionamiento.
Además de lo rápido que logramos hacer el desarrollo hay otra cuestión muy importante a tener en cuenta: es robusto. Más allá de que el ejemplo es básico, lo hemos probado en IE 8 (una de las peores alternativas para esto, en el sentido de que está totalmente obsoleto a la fecha) y el resultado de funcionamiento es perfecto.
Finalmente lo prolijo que ha quedado nuestro código, ya que claramente quedan bien separadas las responsabilidades del servidor y del cliente. Solamente debemos ser prolijos y cuidadosos con las firmas de los métodos que expone cada parte, ya que es allí donde está el acoplamiento y enlace entre las dos partes.

Les comento que he subido el proyecto de este ejemplo a GitHub, para que el que quiera pueda bajarlo, validar algunos puntos y hacer sus propias pruebas: https://github.com/diegobersano/SignalR-Demo
En las siguientes entradas seguiremos profundizando en algunos aspectos que tenemos disponibles con SignalR, los cuales iremos aplicando sobre el mismo proyecto y por consiguiente actualizando el repositorio de GitHub.

No hay comentarios:

Publicar un comentario