Funcionamiento de ASP.NET Core SignalR

Completado

Servidores y la clase Hub

La clase Hub es un concepto de servidor de SignalR. Se define dentro del espacio de nombres Microsoft.AspNetCore.SignalR y forma parte del paquete de NuGet Microsoft.AspNetCore.SignalR. Las aplicaciones web de ASP.NET Core que tienen como destino el SDK de Microsoft.NET.Sdk.Web no necesitan agregar una referencia de paquete para SignalR, ya que ya están disponible como parte del marco compartido.

Hub se expone a través de una ruta. Por ejemplo, la ruta https://www.contoso-pizza.com/hubs/orders se podría usar para representar una implementación de OrdersHub. Mediante las distintas API del centro de conectividad, los autores pueden definir métodos y eventos.

Hay dos modalidades para exponer métodos en un centro de conectividad. Crea una subclase de los siguientes tipos y escribe métodos:

  • Hub: centro de conectividad estándar.
  • Hub<T>: centro de conectividad genérico fuertemente tipado.

Por ejemplo, Hub

Como punto de referencia, tenga en cuenta el siguiente objeto Notification:

namespace RealTime.Models;

public record Notification(string Text, DateTime Date);

El objeto se puede compartir cuando se usa el SDK de cliente de .NET, de modo que el servidor y el cliente tengan exactamente el mismo objeto. Imagine un centro de notificaciones:

using Microsoft.AspNetCore.SignalR;
using System;
using System.Threading.Tasks;
using RealTime.Models;

namespace ExampleServer.Hubs;

public sealed class NotificationHub : Hub
{
    public Task NotifyAll(Notification notification) =>
        Clients.All.SendAsync("NotificationReceived", notification);
}

Cuando se habla de la diferencia entre métodos y eventos, el método en la implementación del centro de conectividad anterior es NotifyAll, mientras que el evento es NotificationReceived. El objeto NotificationHub es una subclase de Hub. El método NotifyAll devuelve un Task y acepta un único parámetro Notification. El método se expresa como la invocación a SendAsync desde Clients.All, que representa todos los clientes conectados. Se desencadena el evento NotificationReceived, en función de la instancia de notification.

Instancia de IHubContext

Desencadenará eventos desde una instancia de Hub o de IHubContext. El centro de SignalR es la abstracción básica para enviar mensajes a los clientes que están conectados al servidor de SignalR. También es posible enviar mensajes desde otros lugares de la aplicación mediante cualquiera de los siguientes tipos:

  • IHubContext<THub>: un contexto en el que THub representa un centro de conectividad estándar.
  • IHubContext<THub,T>: Un contexto en el que THub representa un centro de conectividad genérico fuertemente tipado y T representa el tipo de cliente correspondiente.

Importante

IHubContext es para enviar notificaciones a los clientes. No se usa para llamar a los métodos de Hub.

Ejemplo de IHubContext

Teniendo en cuenta la implementación del centro de notificaciones anterior, podría usar un objeto IHubContext<NotificationHub> de la siguiente manera:

using Microsoft.AspNetCore.SignalR;
using System;
using System.Threading.Tasks;
using RealTime.Models;

namespace ExampleServer.Services;

public sealed class NotificationService(
    IHubContext<NotificationHub> hubContext)
{
    public Task SendNotificationAsync(Notification notification) =>
        notification is not null
            ? hubContext.Clients.All.SendAsync("NotificationReceived", notification)
            : Task.CompletedTask;
}

El código de C# anterior se basa en IHubContext<NotificationHub> para acceder a la lista contextual de clientes, lo que expone la capacidad de difundir notificaciones. El parámetro hubContext del constructor principal que se captura en el ámbito se usa para desencadenar el evento "NotificationReceived", pero no está diseñado para usarse para llamar al método del centro NotifyAll.

Métodos

Los métodos Hub o Hub<T> son igual que cualquier otro método de C#. Definen un tipo de valor devuelto, un nombre de método y parámetros.

  • El tipo de valor devuelto más común para un método de centro es Task o Task<TResult>, que representan la operación de centro asincrónica.
  • El nombre del método se usa para llamar al método desde los clientes. Puede personalizarlo mediante HubMethodNameAttribute.
  • Los parámetros son opcionales, pero cuando se definen, se espera que los clientes proporcionen los argumentos correspondientes.

Los métodos no son necesarios para desencadenar eventos, pero, a menudo, realizan esta función.

Eventos

Se puede suscribir a un evento por el nombre desde un cliente. El servidor es responsable de generar eventos. Los eventos Hub, Hub<T>, IHubContext<THub> y IHubContext<THub, T> se nombran y pueden definir hasta 10 parámetros. Los eventos se desencadenan en el servidor y los administran los clientes interesados. Se considera que un cliente está interesado cuando se suscribe a eventos en la conexión del centro correspondiente. Los clientes pueden desencadenar indirectamente eventos cuando llaman a métodos del centro de conectividad que desencadenan eventos como resultado de su invocación. Sin embargo, los clientes no pueden desencadenar directamente eventos, ya que esa es responsabilidad del servidor.

Ámbitos de clientes de eventos

Los eventos se llaman desde una instancia de IClientProxy. Las interfaces IHubClients y IHubCallerClients se implementan a partir del tipo Clients. Hay muchas maneras de establecer el ámbito de una instancia de IClientProxy específica. Puede dirigirse a los siguientes ámbitos desde la propiedad Hub.Clients:

Miembro Detalles
All Todos los clientes conectados (por ejemplo, una difusión).
AllExcept Todos los clientes conectados, excepto las conexiones especificadas (por ejemplo, una difusión filtrada).
Caller El cliente conectado que desencadenó el método (por ejemplo, un eco).
Client La conexión de cliente especificada (conexión única).
Clients Las conexiones de cliente especificadas (varias conexiones).
Group Todos los clientes conectados dentro del grupo especificado.
GroupExcept Todos los clientes conectados dentro del grupo especificado, excepto las conexiones especificadas.
Groups Todos los clientes conectados dentro de los grupos especificados (varios grupos).
Others Todos los clientes conectados, excepto el cliente que desencadenó el método.
OthersInGroup Todos los clientes conectados dentro del grupo especificado, excepto el cliente que desencadenó el método.
User Todos los clientes conectados para el usuario especificado (un solo usuario puede conectarse en más de un dispositivo).
Users Todos los clientes conectados para los usuarios especificados.

Ámbitos de ejemplo

Tenga en cuenta las siguientes imágenes, que pueden ayudarle a visualizar cómo el centro de conectividad envía mensajes a los clientes de destino. Puede expandir las imágenes para mejorar la legibilidad.

  • Difusión a todos

    ASP.NET Core SignalR hub sending message with Clients.All syntax.

    Todos los clientes conectados reciben este mensaje, independientemente del grupo al que puedan pertenecer o no.

  • Usuario aislado

    ASP.NET Core SignalR hub sending message with Clients.User syntax.

    Un solo usuario recibe este mensaje, independientemente de cuántos dispositivos use actualmente.

  • Grupo aislado

    ASP.NET Core SignalR hub sending message with Clients.Group syntax.

    Solo los clientes que pertenecen a un grupo determinado reciben este mensaje.

Clientes y la clase HubConnection

La clase HubConnection es un concepto de cliente de SignalR, que representa la conexión del cliente con el objeto Hub del servidor. Se define dentro del espacio de nombres Microsoft.AspNetCore.SignalR.Client y forma parte del paquete NuGet Microsoft.AspNetCore.SignalR.Client.

Se crea un objeto HubConnection mediante el patrón del generador y el tipo HubConnectionBuilder correspondiente. Dada la ruta del centro de conectividad (o System.Uri) se puede crear un HubConnection. El generador también puede especificar opciones de configuración adicionales, como el registro, el protocolo deseado, el reenvío de tokens de autenticación y la reconexión automática, entre otras.

La API HubConnection expone las funciones de inicio y detención que se usan para iniciar y detener la conexión al servidor. Además, hay funcionalidades para hacer streaming, llamar a métodos de centro y suscribirse a eventos.

Ejemplo de creación de HubConnection

Para crear un objeto HubConnection a partir del SDK de cliente de SignalR para .NET, se usa el tipo HubConnectionBuilder:

using Microsoft.AspNetCore.SignalR.Client;
using System;
using System.Threading.Tasks;
using RealTime.Models;

namespace ExampleClient;

public sealed class Consumer : IAsyncDisposable
{
    private readonly string HostDomain =
        Environment.GetEnvironmentVariable("HOST_DOMAIN");
    
    private HubConnection _hubConnection;

    public Consumer()
    {
        _hubConnection = new HubConnectionBuilder()
            .WithUrl(new Uri($"{HostDomain}/hub/notifications"))
            .WithAutomaticReconnect()
            .Build();
    }

    public Task StartNotificationConnectionAsync() =>
        _hubConnection.StartAsync();

    public async ValueTask DisposeAsync()
    {
        if (_hubConnection is not null)
        {
            await _hubConnection.DisposeAsync();
            _hubConnection = null;
        }
    }
}

Métodos del centro de llamadas

Si a un cliente se le proporciona una instancia de HubConnection de cliente que se ha iniciado correctamente, ese cliente puede llamar a los métodos de un centro de conectividad mediante las extensiones InvokeAsync o SendAsync. Si el método del centro de conectividad devuelve un objeto Task<TResult>, el resultado del objeto InvokeAsync<TResult> es de tipo TResult. Si el método de centro de conectividad devuelve Task, no habrá ningún resultado. Tanto InvokeAsync como SendAsync requieren el nombre del método del centro y de cero a diez parámetros.

  • InvokeAsync: invoca un método de centro de conectividad en el servidor con el nombre de método y los argumentos opcionales especificados.
  • SendAsync: invoca un método de centro de conectividad en el servidor con el nombre de método y los argumentos opcionales especificados. Este método no espera una respuesta del receptor.

Ejemplo de invocación de método de centro de conectividad

Cuando SendNotificationAsync agrega un método a la clase Consumer anterior, SendNotificationAsync delega en _hubConnection y llama al método NotifyAll en el centro de conectividad del servidor, según la instancia de Notification.

public Task SendNotificationAsync(string text) =>
    _hubConnection.InvokeAsync(
        "NotifyAll", new Notification(text, DateTime.UtcNow));

Control de eventos

Para controlar eventos, deberá registrar un controlador con la instancia HubConnection. Llame a una de las sobrecargas de HubConnectionExtensions.On cuando conozca el nombre del método de centro de conectividad y tenga de cero a ocho parámetros. El controlador puede satisfacer cualquiera de las variaciones de Action siguientes:

Como alternativa, puede usar las API de controlador asincrónicas que son Func<TResult>, donde TResult es una variación de Task:

El resultado de registrar un controlador de eventos es un IDisposable, que actúa como suscripción. Para cancelar la suscripción del controlador, llame a Dispose.

Ejemplo de registro de eventos

Al actualizar la clase Consumer anterior, se proporciona un controlador y se llama a On para registrar un evento:

using Microsoft.AspNetCore.SignalR.Client;
using System;
using System.Threading.Tasks;
using RealTime.Models;

namespace ExampleClient;

public sealed class Consumer : IAsyncDisposable
{
    private readonly string HostDomain =
        Environment.GetEnvironmentVariable("HOST_DOMAIN");
    
    private HubConnection _hubConnection;

    public Consumer()
    {
        _hubConnection = new HubConnectionBuilder()
            .WithUrl(new Uri($"{HostDomain}/hub/notifications"))
            .WithAutomaticReconnect()
            .Build();

        _hubConnection.On<Notification>(
            "NotificationReceived", OnNotificationReceivedAsync);
    }

    private async Task OnNotificationReceivedAsync(Notification notification)
    {
        // Do something meaningful with the notification.
        await Task.CompletedTask;
    }

    // Omitted for brevity.
}

Se llama al método OnNotificationReceivedAsync cuando la instancia de centro del servidor desencadena el evento "NotificationReceived".

Actualizaciones de pedidos en tiempo real de Contoso Pizza

El código de servidor de la aplicación web debe tener una implementación de Hub y exponer una ruta a los clientes. El objeto Hub podría usar el identificador único del objeto del pedido para crear un grupo para el seguimiento. Todas las actualizaciones de cambio de estado del pedido se podrían comunicar en este grupo.

El código de cliente también tendría que actualizarse para indicar que la aplicación Contoso Pizza es una aplicación de Blazor WebAssembly. Puede usar el SDK de JavaScript o el SDK de cliente de .NET. Así reemplazaría la funcionalidad de sondeo del lado cliente por código que compile un objeto HubConnection e iniciará la conexión con el servidor. A medida que se desplaza a la página de seguimiento de pedidos, el código tendría que unirse al grupo específico del pedido donde se enviarán las actualizaciones de los cambios. Se suscribiría al evento de cambios de estado del pedido y, luego, lo controlaría en consecuencia.