Funzionamento di SignalR ASP.NET Core
Server e classe Hub
La classe Hub
è un concetto di server SignalR. Viene definita all'interno dello spazio dei nomi Microsoft.AspNetCore.SignalR
e fa parte del pacchetto NuGet Microsoft.AspNetCore.SignalR. ASP.NET app Web core destinate a Microsoft.NET.Sdk.Web SDK non devono aggiungere un riferimento al pacchetto per SignalR, perché è già disponibile come parte del framework condiviso.
Un Hub
oggetto viene esposto tramite una route. Ad esempio, si può usare la route https://www.contoso-pizza.com/hubs/orders
per rappresentare un'implementazione OrdersHub
. Tramite le varie API dell'hub, gli autori possono definire metodi ed eventi.
Per esporre i metodi in un hub sono disponibili due modalità. Creare una sottoclasse dei tipi e dei metodi di scrittura seguenti:
EsempioHub
Come punto di riferimento, considerare l'oggetto Notification
seguente:
namespace RealTime.Models;
public record Notification(string Text, DateTime Date);
L'oggetto può essere condiviso quando si usa .NET client SDK, in modo che il server e il client abbiano esattamente lo stesso oggetto. Si immagini un hub di notifica:
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);
}
Per quanto riguarda la differenza tra metodi ed eventi, il metodo nell'implementazione dell'hub precedente è NotifyAll
e l'evento è NotificationReceived
. NotificationHub
è una sottoclasse di Hub
. Il NotifyAll
metodo restituisce un Task
oggetto e accetta un singolo Notification
parametro. Il metodo viene espresso come chiamata a SendAsync
da Clients.All
, che rappresenta tutti i client connessi. Viene generato l'evento NotificationReceived
, a seconda dell'istanza di notification
.
Istanza di IHubContext
Gli eventi vengono generati da un'istanza IHubContext
Hub
di o . L'hub SignalR è il fulcro dell'astrazione per l'invio di messaggi ai client connessi al server SignalR. È anche possibile inviare messaggi da altre posizioni dell'app usando uno dei tipi seguenti:
- IHubContext<THub>: contesto in cui
THub
rappresenta un hub standard. - IHubContext<THub,T>: contesto in cui
THub
rappresenta un hub generico fortemente tipizzato eT
rappresenta il tipo di client corrispondente.
Importante
IHubContext
è per l'invio di notifiche ai client. Non viene usato per chiamare i metodi in Hub
.
Ad esempio, IHubContext
Considerando l'implementazione precedente dell'hub di notifica, è possibile usare IHubContext<NotificationHub>
come segue:
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;
}
Il codice C# precedente si basa su IHubContext<NotificationHub>
per accedere all'elenco contestuale dei client, esponendo la possibilità di trasmettere le notifiche. Il parametro hubContext
del costruttore primario acquisito nell'ambito viene usato per generare l'evento "NotificationReceived"
, ma non è destinato a essere usato per chiamare il metodo NotifyAll
dell'hub.
Metodi
I metodi Hub
o Hub<T>
sono esattamente uguali a qualsiasi altro metodo C#. Definiscono un tipo restituito, un nome di metodo e parametri.
- Il tipo restituito più comune per un metodo hub è
Task
oTask<TResult>
, che rappresenta l'operazione asincrona dell'hub. - Il nome del metodo viene usato per chiamare il metodo dai client. Può essere personalizzato usando HubMethodNameAttribute.
- I parametri sono facoltativi, ma se vengono definiti i client devono fornire argomenti corrispondenti.
I metodi non sono necessari per generare eventi, sebbene spesso lo facciano.
evento
Un evento può essere sottoscritto in base al nome da un client. Il server è responsabile della generazione di eventi. Hub
Gli eventi , Hub<T>
IHubContext<THub>
, e IHubContext<THub, T>
sono denominati e possono definire fino a 10 parametri. Gli eventi vengono generati nel server e sono gestiti dai client interessati. Un client è considerato interessato quando sottoscrive gli eventi sulla connessione dell'hub. I client possono attivare indirettamente gli eventi quando chiamano metodi hub che generano eventi risultanti dalla chiamata. Gli eventi non possono tuttavia essere attivati direttamente dai client, perché è responsabilità del server.
Ambiti client di eventi
Chiamare gli eventi da un'istanza di IClientProxy. Implementare le interfacce IHubClients e IHubCallerClients dal tipo Clients. Esistono molti modi per definire l'ambito di un'istanza di IClientProxy
specifica. È possibile specificare come destinazione gli ambiti seguenti dalla proprietà Hub.Clients
:
Membro | Dettagli |
---|---|
All |
Tutti i client connessi, ad esempio una trasmissione. |
AllExcept |
Tutti i client connessi, escluse le connessioni specificate, ad esempio una trasmissione filtrata. |
Caller |
Il client connesso che ha attivato il metodo, ad esempio un echo. |
Client |
La connessione client specificata (singola connessione). |
Clients |
Le connessioni client specificate (più connessioni). |
Group |
Tutti i client connessi all'interno del gruppo specificato. |
GroupExcept |
Tutti i client connessi all'interno del gruppo specificato, escluse le connessioni specificate. |
Groups |
Tutti i client connessi all'interno dei gruppi specificati (più gruppi). |
Others |
Tutti i client connessi, escluso il client che ha attivato il metodo. |
OthersInGroup |
Tutti i client connessi all'interno del gruppo specificato, escluso il client che ha attivato il metodo. |
User |
Tutti i client connessi per l'utente specificato (un singolo utente può connettersi su più di un dispositivo). |
Users |
Tutti i client connessi per gli utenti specificati. |
Ambiti di esempio
Osservare le immagini seguenti, che consentono di visualizzare il modo in cui l'hub invia messaggi ai client di destinazione. È possibile espandere le immagini per migliorare la leggibilità.
Trasmettere a tutti
Tutti i client connessi ricevono questo messaggio, indipendentemente dal gruppo a cui potrebbero o meno appartenere.
Utente isolato
Un singolo utente riceve questo messaggio, indipendentemente dal numero di dispositivi attualmente in uso.
Gruppo isolato
Solo i client che appartengono a un determinato gruppo ricevono questo messaggio.
Client e classe HubConnection
La classe HubConnection
è un concetto di client SignalR, che rappresenta la connessione del client al server Hub
. Viene definita all'interno dello spazio dei nomi Microsoft.AspNetCore.SignalR.Client
e fa parte del pacchetto NuGet Microsoft.AspNetCore.SignalR.Client.
Si crea un HubConnection
oggetto usando il modello di generatore e il tipo corrispondente HubConnectionBuilder
. Data la route dell'hub (o System.Uri), è possibile creare un oggetto HubConnection
. Il generatore può anche specificare opzioni di configurazione aggiuntive, tra cui la registrazione, il protocollo desiderato, l'inoltro dei token di autenticazione e la riconnessione automatica.
L'API HubConnection
espone le funzioni di avvio e arresto, usate per avviare e arrestare la connessione al server. Sono anche disponibili funzionalità per lo streaming, la chiamata ai metodi dell'hub e la sottoscrizione agli eventi.
Esempio di creazione di un oggetto HubConnection
Per creare un oggetto HubConnection
dall'SDK client .NET SignalR, usare il 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;
}
}
}
Chiamare i metodi dell'hub
Se a un client viene assegnata un'istanza client HubConnection
che è stata avviata correttamente, tale client può chiamare i metodi in un hub usando le InvokeAsync estensioni o SendAsync . Se il metodo hub restituisce un oggetto Task<TResult>
, il risultato di InvokeAsync<TResult>
è di tipo TResult
. Se il metodo hub restituisce Task
, non si ottiene alcun risultato. Sia InvokeAsync
che SendAsync
richiedono il nome del metodo hub e zero a 10 parametri.
- InvokeAsync: chiama un metodo hub nel server usando il nome del metodo e gli argomenti facoltativi specificati.
- SendAsync: chiama un metodo hub nel server usando il nome del metodo e gli argomenti facoltativi specificati. Questo metodo non attende una risposta dal destinatario.
Esempio di chiamata al metodo hub
Quando SendNotificationAsync
aggiunge un metodo alla classe precedente Consumer
, SendNotificationAsync
delega all'oggetto _hubConnection
e chiama il NotifyAll
metodo nell'hub del server, a seconda dell'istanza Notification
.
public Task SendNotificationAsync(string text) =>
_hubConnection.InvokeAsync(
"NotifyAll", new Notification(text, DateTime.UtcNow));
Gestire eventi
Per gestire gli eventi, registrare un gestore con l'istanza di HubConnection
. Chiamare uno degli overload HubConnectionExtensions.On quando il nome del metodo hub è noto e si hanno da zero a otto parametri. Il gestore può soddisfare una delle varianti Action
seguenti:
- 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>
In alternativa, è possibile usare le API del gestore asincrono, che sono Func<TResult>
dove è TResult
una variante 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>
Il risultato della registrazione di un gestore eventi è un IDisposable
oggetto , che funge da sottoscrizione. Per annullare la sottoscrizione del gestore, chiamare Dispose.
Esempio di registrazione di un evento
Aggiornando la classe Consumer
precedente, si esegue la registrazione a un evento specificando un gestore e chiamando On
:
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.
}
Il metodo OnNotificationReceivedAsync
viene chiamato quando l'istanza dell'hub del server genera l'evento "NotificationReceived"
.
Aggiornamenti degli ordini live di Contoso Pizza
Il codice del server per l'applicazione Web deve avere un'implementazione Hub
ed esporre una route ai client. Hub
può usare l'identificatore univoco dell'oggetto ordine per creare un gruppo per il rilevamento. Tutti gli aggiornamenti delle modifiche dello stato dell'ordine possono quindi essere comunicati in questo gruppo.
Il codice client deve anche essere aggiornato per indicare che l'applicazione Contoso Pizza è un'app WebAssembly Blazor. È possibile usare JavaScript SDK o .NET Client SDK. Si sostituirà la funzionalità di polling sul lato client con il codice che compila un oggetto HubConnection
e quindi si avvierà la connessione al server. Una volta passato alla pagina di monitoraggio dell'ordine, il codice dovrà unirsi al gruppo specifico dell'ordine a cui verranno inviati gli aggiornamenti delle modifiche. Si sottoscriverà l'evento per le modifiche dello stato dell'ordine e quindi gestirlo di conseguenza.