Funcionamiento de ASP.NET Core SignalR
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:
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 yT
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
oTask<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
Todos los clientes conectados reciben este mensaje, independientemente del grupo al que puedan pertenecer o no.
Usuario aislado
Un solo usuario recibe este mensaje, independientemente de cuántos dispositivos use actualmente.
Grupo aislado
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:
- Action
- Action<T>
- Action<T1,T2>
- Action<T1,T2,T3>
- Action<T1,T2,T3,T4>
- Action<T1,T2,T3,T4,T5>
- Action<T1,T2,T3,T4,T5,T6>
- Action<T1,T2,T3,T4,T5,T6,T7>
- Action<T1,T2,T3,T4,T5,T6,T7,T8>
Como alternativa, puede usar las API de controlador asincrónicas que son Func<TResult>
, donde TResult
es una variación de Task
:
Func<Task>
Func<T,Task>
Func<T1,T2,Task>
Func<T1,T2,T3,Task>
Func<T1,T2,T3,T4,Task>
Func<T1,T2,T3,T4,T5,Task>
Func<T1,T2,T3,T4,T5,T6,Task>
Func<T1,T2,T3,T4,T5,T6,T7,Task>
Func<T1,T2,T3,T4,T5,T6,T7,T8,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.