Introducción a SignalR

por Patrick Fletcher

Advertencia

Esta documentación no se aplica a la última versión de SignalR. Eche un vistazo a SignalR de ASP.NET Core.

Este artículo describe qué es SignalR y algunas de las soluciones para cuya creación se ha diseñado.

Preguntas y comentarios

Deje sus comentarios sobre este tutorial y sobre lo que podríamos mejorar en los comentarios en la parte inferior de la página. Si tiene alguna pregunta que no esté directamente relacionadas con el tutorial, puede publicarla en el foro de SignalR de ASP.NET o en StackOverflow.com.

¿Qué es SignalR?

SignalR de ASP.NET es una biblioteca para los desarrolladores de ASP.NET que simplifica el proceso de agregar funcionalidad web en tiempo real a las aplicaciones. La funcionalidad web en tiempo real es la capacidad de disponer de contenidos de inserción de código de servidor en clientes conectados al instante, a medida que van estando disponibles, en lugar de que el servidor tenga que esperar que un cliente solicite nuevos datos.

Puede utilizarse SignalR para añadir cualquier tipo de funcionalidad web en tiempo real a una aplicación ASP.NET. Se suele poner como ejemplo el chat, pero se puede hacer mucho más. Un usuario es un posible candidato para el uso de SignalR cada vez que actualiza una página web para ver nuevos datos, o cuando la página ejecuta sondeos largos para recuperar nuevos datos. Algunos ejemplos son los paneles y las aplicaciones de supervisión, las aplicaciones colaborativas (p. ej., edición simultánea de documentos), las actualizaciones de progreso del trabajo y los formularios en tiempo real.

SignalR también permite tipos completamente nuevos de aplicaciones web que requieren actualizaciones de alta frecuencia del servidor, como los juegos en tiempo real.

SignalR ofrece una API sencilla para crear llamadas de procedimiento remoto (RPC) de servidor a cliente que llaman a funciones JavaScript en exploradores cliente (y otras plataformas cliente) desde código .NET de servidor. SignalR también incluye API para la administración de conexiones (por ejemplo, eventos de conexión y desconexión) y la agrupación de conexiones.

Invoking methods with SignalR

SignalR controla automáticamente la administración de conexiones y permite difundir mensajes a todos los clientes conectados de forma simultánea, como un salón de chat. También se pueden enviar mensajes a clientes concretos. La conexión entre el cliente y el servidor es persistente, a diferencia de una conexión HTTP clásica, que se vuelve a establecer para cada comunicación.

SignalR admite la función "server push", con la que el código de servidor puede llamar al código de cliente en el explorador mediante llamadas a procedimientos remotos (RPC), en lugar del modelo de solicitud-respuesta habitual en la web en la actualidad.

Las aplicaciones SignalR se pueden escalar horizontalmente a miles de clientes mediante proveedores integrados y de terceros de escalado horizontal.

Entre los proveedores integrados se encuentran los siguientes:

Entre los proveedores de terceros se encuentran los siguientes

SignalR es de código abierto y es accesible a través de GitHub.

SignalR y WebSocket

SignalR usa el nuevo transporte de WebSocket cuando está disponible, y regresa a los transportes más antiguos cuando es necesario. Si bien es cierto que podría escribir la aplicación directamente mediante WebSocket, el uso de SignalR hace por usted que una gran parte de las funciones adicionales que tendría que ejecutar. Y lo que es más importante: esto significa que puede codificar la aplicación para aprovechar WebSocket sin tener que preocuparse de crear una ruta de acceso de código independiente para clientes más antiguos. Además, SignalR evita tener que preocuparse por las actualizaciones de WebSocket, ya que se actualiza para admitir los cambios en el transporte subyacente, lo que dota a la aplicación de una interfaz coherente entre versiones de WebSocket.

Transportes y reservas

SignalR es una abstracción sobre algunos de los transportes necesarios para llevar a cabo el trabajo en tiempo real entre el cliente y el servidor. En primer lugar, SignalR trata de establecer una conexión WebSocket, si es posible. WebSocket es el transporte óptimo para SignalR porque ofrece:

  • el uso más eficiente de la memoria del servidor;
  • la latencia más baja;
  • las características más subyacentes, como la comunicación dúplex completa entre el cliente y el servidor;
  • los requisitos más estrictos, ya que WebSocket requiere que el servidor:
    • se ejecute en Windows Server 2012 o Windows 8.
    • .NET Framework 4.5.

Si no se cumplen estos requisitos, SignalR intenta utilizar otros transportes para ejecutar sus conexiones.

Transportes HTML 5

Estos transportes dependen de la compatibilidad con HTML 5. Si el explorador cliente no admite el estándar HTML 5, se utilizarán los transportes más antiguos.

  • WebSocket (si el servidor y el explorador indican que pueden hay compatibilidad con WebSocket). WebSocket es el único transporte que establece una auténtica conexión bidireccional persistente entre el cliente y el servidor. Sin embargo, WebSocket también exige los requisitos más estrictos; solo es totalmente compatible con las versiones más recientes de Microsoft Internet Explorer, Google Chrome y Mozilla Firefox, y solo está parcialmente implantado en otros exploradores, como Opera y Safari.
  • Eventos enviados del servidor, también conocidos como EventSource (si el explorador es compatible con los eventos enviados del servidor, como ocurre con, básicamente, todos los exploradores salvo Internet Explorer).

Transportes Comet

Los transportes siguientes se basan en el modelo de aplicación web Comet, en el que un explorador u otro cliente mantiene una solicitud HTTP de larga duración, que el servidor puede usar para introducir datos en el cliente sin que este lo solicite específicamente.

  • Forever Frame (solo para Internet Explorer). Forever Frame crea un IFrame oculto que ejecuta una solicitud a un punto de conexión en el servidor que no se completa. A continuación, el servidor envía continuamente un script al cliente que se ejecuta inmediatamente, lo que facilita una conexión en tiempo real unidireccional desde el servidor al cliente. La conexión del cliente al servidor utiliza una conexión independiente de la del servidor al cliente; al igual que ocurre con una solicitud HTTP estándar, se crea una nueva conexión para cada fragmento de datos que se debe enviar.
  • Sondeos largos Ajax . Los sondeos largos no crean una conexión persistente, sino que sondean el servidor con una solicitud que permanece abierta hasta que el servidor responda, momento en el que se termina la conexión y se solicita inmediatamente una nueva. Esto puede provocar cierta latencia durante el tiempo que tarda en restablecerse la conexión.

Para obtener más información sobre qué transportes se admiten y en qué configuraciones, véase la sección Plataformas compatibles.

Proceso de selección de transporte

En la lista siguiente se muestran los pasos que SignalR usa para decidir qué transporte utilizar.

  1. Si el explorador es Internet Explorer 8 o versiones anteriores, se utiliza el sondeo largo.

  2. Si está configurado JSONP (es decir, se establece el valor true para el parámetro jsonp cuando se inicia la conexión), se utiliza el sondeo largo.

  3. Si se establece una conexión entre dominios (es decir, si el punto de conexión de SignalR no está en el mismo dominio que la página de hospedaje), se usará WebSocket si se cumplen los siguientes criterios:

    • el cliente admite CORS (siglas en inglés de «uso compartido de recursos entre orígenes»). Para más información sobre qué clientes admiten CORS, consulte CORS en caniuse.com;

    • el cliente admite WebSocket;

    • el servidor admite WebSocket.

      Si no se cumple alguno de estos criterios, se usará el sondeo largo. Para obtener más información sobre las conexiones entre dominios, véase la sección Establecimiento de una conexión entre dominios.

  4. Si JSONP no está configurado y la conexión no es entre dominios, se usará WebSocket si tanto el cliente como el servidor lo admiten.

  5. Si el cliente o el servidor no admiten WebSocket, se utilizan los eventos enviados por el servidor si están disponibles.

  6. Si los eventos enviados por el servidor no están disponibles, se procede con un intento de Forever Frame.

  7. Si Forever Frame falla, se emplea el sondeo largo.

Supervisión de transportes

Para determinar qué transporte utiliza la aplicación, habilite el registro en su centro y abra la ventana de la consola en su explorador.

Para habilitar el registro de los eventos de su centro en un explorador, agregue el siguiente comando a la aplicación cliente:

$.connection.hub.logging = true;

  • En Internet Explorer, pulse F12 para abrir las herramientas de desarrollo y haga clic en la pestaña «Consola».

    Console in Microsoft Internet Explorer

  • En Chrome, pulse Ctrl+Mayús+J para abrir la consola.

    Console in Google Chrome

Con la consola abierta y el registro habilitados, podrá ver qué transporte utiliza SignalR.

Console in Internet Explorer showing WebSocket transport

Especificación de un transporte

La negociación de un transporte tarda algo de tiempo y consume recursos del cliente/servidor. Si se conocen las capacidades del cliente, se puede especificar un transporte cuando se inicia la conexión de cliente. El siguiente fragmento de código muestra cómo iniciar una conexión mediante el transporte de sondeo largo de Ajax, tal y como se usaría si se constatase que el cliente no admite ningún otro protocolo:

connection.start({ transport: 'longPolling' });

Puede especificar un pedido de reserva si desea que un cliente pruebe transportes específicos en orden. El siguiente fragmento de código muestra un intento fallido WebSocket que da paso directamente al sondeo largo.

connection.start({ transport: ['webSockets','longPolling'] });

Las constantes de cadena para especificar transportes se definen de la siguiente manera:

  • webSockets
  • foreverFrame
  • serverSentEvents
  • longPolling

Conexiones y concentradores

La API de SignalR contiene dos modelos para comunicarse entre clientes y servidores: conexiones persistentes y concentradores.

Una conexión representa un punto de conexión simple para enviar mensajes de un solo destinatario, agrupados o de difusión. La API de conexión persistente (representada en código de .NET por la clase PersistentConnection) brinda al desarrollador acceso directo al protocolo de comunicación de bajo nivel que expone SignalR. Es probable que los desarrolladores que hayan usado API basadas en conexiones, como Windows Communication Foundation, estén familiarizados con el uso del modelo de comunicación de conexiones.

Un concentrador es una canalización de alto nivel basada en la API de conexión que permite que el cliente y el servidor llamen a métodos directamente entre ellos. SignalR se encarga del envío en los límites de la máquina como por arte de magia, lo que permite a los clientes llamar a métodos en el servidor y viceversa. Los desarrolladores que hayan usado API de invocación remota, como .NET Remoting, estarán familiarizados con el uso del modelo de comunicación de concentradores. El uso de un concentrador también permite transferir parámetros eminentemente de tipo a métodos, lo que permite el enlace de modelos.

Diagrama de la arquitectura

En el diagrama siguiente se muestra la relación entre concentradores, conexiones persistentes y las tecnologías subyacentes empleadas para los transportes.

SignalR Architecture Diagram showing APIs, transports, and clients

Funcionamiento de los concentradores

Cuando el código del lado servidor llama a un método en el cliente, se envía un paquete a través del transporte activo que contiene el nombre y los parámetros del método al que se va a llamar (cuando se envía un objeto como parámetro de método, se serializa mediante JSON). A continuación, el cliente asocia el nombre del método a los métodos definidos en el código del lado cliente. Si hay una coincidencia, el método cliente se ejecutará mediante los datos del parámetro deserializado.

La llamada al método se puede supervisar mediante herramientas como Fiddler. En la imagen siguiente se muestra una llamada de método enviada desde un servidor de SignalR a un cliente de explorador web en el panel de registros de Fiddler. La llamada al método se envía desde un concentrador denominado MoveShapeHub, y el método que se invoca se denomina updateShape.

View of Fiddler log showing SignalR traffic

En este ejemplo, el nombre del concentrador se identifica con el parámetro H, el nombre del método se identifica con el parámetro M y los datos que se envían al método se identifican con el parámetro A. La aplicación que generó este mensaje se crea en el tutorial de tiempo real de alta frecuencia.

Selección de un modelo de comunicación

La mayoría de las aplicaciones tienen que usar la API de concentradores. La API de conexiones se puede usar en las siguientes circunstancias:

  • es necesario especificar el formato del mensaje real enviado;
  • el desarrollador prefiere trabajar con un modelo de mensajería y distribución en lugar de un modelo de invocación remota;
  • se está migrando una aplicación existente que emplea un modelo de mensajería para el uso de SignalR.