Funktionsweise von ASP.NET Core SignalR
Server und die Hub
-Klasse
Die Hub
-Klasse ist ein SignalR-Serverkonzept. Sie ist im Microsoft.AspNetCore.SignalR
-Namespace definiert und Teil des NuGet-Pakets Microsoft.AspNetCore.SignalR. ASP.NET Core-Webanwendungen, die auf das Microsoft.NET.Sdk.Web SDK abzielen, müssen keinen Paketverweis für SignalR hinzufügen, da es bereits als Teil des gemeinsamen Frameworks verfügbar ist.
Ein Hub
wird über eine Route verfügbar gemacht. Die Route https://www.contoso-pizza.com/hubs/orders
kann beispielsweise verwendet werden, um eine OrdersHub
-Implementierung darzustellen. Mit den verschiedenen Hub-APIs können Ersteller Methoden und Ereignisse definieren.
Es gibt zwei Möglichkeiten, Methoden auf einem Hub verfügbar zu machen. Sie erstellen eine Unterklasse der folgenden Typen und schreiben Methoden:
Beispiel: Hub
Sehen Sie sich als Referenz das folgende Notification
-Objekt an:
namespace RealTime.Models;
public record Notification(string Text, DateTime Date);
Das Objekt kann freigegeben werden, wenn das .NET-Client-SDK verwendet wird, damit der Server und der Client genau das gleiche Objekt aufweisen. Stellen Sie sich einen Notification Hub vor:
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);
}
Was den Unterschied zwischen Methoden und Ereignissen betrifft, so ist die Methode in der vorangegangenen Hub-Implementierung NotifyAll
und das Ereignis ist NotificationReceived
. NotificationHub
ist eine Unterklasse von Hub
. Die NotifyAll
-Methode gibt einen Task
an und akzeptiert einen einzelnen Notification
-Parameter. Die Methode wird als Aufruf von SendAsync
aus Clients.All
(steht für alle verbundenen Clients) ausgedrückt. Das Ereignis NotificationReceived
wird abhängig von der notification
-Instanz ausgelöst.
Die IHubContext
-Instanz
Sie lösen Ereignisse entweder über eine Hub
- oder eine IHubContext
-Instanz aus. Der SignalR-Hub ist die zentrale Abstraktion zum Senden von Nachrichten an Clients, die mit dem SignalR-Server verbunden sind. Es ist auch möglich, Nachrichten von anderen Stellen in Ihrer App zu senden, indem Sie einen der folgenden Typen verwenden:
- IHubContext<THub>: Ein Kontext, bei dem
THub
einen Standardhub repräsentiert. - IHubContext<THub,T>: Ein Kontext, bei dem
THub
für den stark typisierten generischen Hub undT
für den entsprechenden Clienttyp steht.
Wichtig
IHubContext
dient zum Senden von Benachrichtigungen an Clients. Dieses Element wird nicht verwendet, um Methoden für den Hub
aufzurufen.
Ein Beispiel für IHubContext
In Anbetracht der vorherigen Implementierung des Notification Hub könnten Sie wie folgt vorgehen IHubContext<NotificationHub>
:
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;
}
Im vorangegangenen C#-Code wird das IHubContext<NotificationHub>
-Element genutzt, um auf die kontextbezogene Clientliste zuzugreifen und so das Senden von Benachrichtigungen zu ermöglichen. Der primäre hubContext
-Konstruktorparameter, der im Bereich erfasst wird, wird verwendet, um das "NotificationReceived"
-Ereignis auszulösen, aber er ist nicht dazu gedacht, die NotifyAll
-Methode des Hubs aufzurufen.
Methoden
Hub
- oder Hub<T>
-Methoden sind wie jede andere C#-Methode. Sie definieren einen Rückgabetyp, einen Methodennamen und Parameter.
- Die häufigsten Rückgabetypen für eine Hubmethode sind
Task
undTask<TResult>
(steht für den asynchronen Hubvorgang). - Der Methodenname wird verwendet, um die Methode von Clients aufzurufen. Sie können ihn über HubMethodNameAttribute anpassen.
- Parameter sind optional, aber wenn sie definiert werden, wird von Clients erwartet, die entsprechenden Argumente bereitzustellen.
Methoden müssen keine Ereignisse auslösen, aber sie tun es oft.
Ereignisse
Ein Ereignis kann anhand des Namens von einem Client abonniert werden. Für das Auslösen von Ereignissen ist der Server zuständig. Die Ereignisse Hub
, Hub<T>
, IHubContext<THub>
und IHubContext<THub, T>
werden bezeichnet und können bis zu 10 Parameter definieren. Ereignisse werden auf dem Server ausgelöst und von interessierten Clients verarbeitet. Ein Client gilt als „interessiert“, wenn er über die Verbindung seines Hubs Ereignisse abonniert. Clients können Ereignisse indirekt auslösen, wenn sie Hubmethoden aufrufen, die als Ergebnis ihres Aufrufs Ereignisse auslösen. Ereignisse können jedoch nicht direkt von Clients ausgelöst werden, da dies in der Verantwortung des Servers liegt.
Ereignisclientbereiche
Sie rufen Ereignisse über eine IClientProxy-Instanz auf. Die Schnittstellen IHubClients und IHubCallerClients werden über den Typ Clients implementiert. Es gibt viele Möglichkeiten, einen Bereich auf eine bestimmte IClientProxy
-Instanz festzulegen. Sie können über die Hub.Clients
-Eigenschaft die folgenden Zielbereiche festlegen:
Member | Details |
---|---|
All |
Alle verbundenen Clients (z. B. für eine Übertragung). |
AllExcept |
Alle verbundenen Clients, mit Ausnahme der angegebenen Verbindungen (z. B. für eine gefilterte Übertragung). |
Caller |
Der verbundene Client, der die Methode ausgelöst hat (z. B. als Echo). |
Client |
Die angegebene Clientverbindung (einzelne Verbindung). |
Clients |
Die angegebenen Clientverbindungen (mehrere Verbindungen). |
Group |
Alle verbundenen Clients innerhalb der angegebenen Gruppe. |
GroupExcept |
Alle verbundenen Clients innerhalb der angegebenen Gruppe, mit Ausnahme der angegebenen Verbindungen. |
Groups |
Alle verbundenen Clients innerhalb der angegebenen Gruppen (mehrere Gruppen). |
Others |
Alle verbundenen Clients, mit Ausnahme des Clients, der die Methode ausgelöst hat. |
OthersInGroup |
Alle verbundenen Clients innerhalb der angegebenen Gruppe, mit Ausnahme des Clients, der die Methode ausgelöst hat. |
User |
Alle verbundenen Clients für den angegebenen Benutzer (ein Benutzer kann über mehrere Geräte eine Verbindung herstellen). |
Users |
Alle verbundenen Clients für die angegebenen Benutzer. |
Beispielbereiche
Die folgenden Abbildungen veranschaulichen, wie der Hub Nachrichten an die Zielclients sendet. Zur besseren Lesbarkeit können Sie die Abbildungen vergrößern.
Übertragen an alle
Alle verbundenen Clients erhalten diese Nachricht unabhängig davon, welcher Gruppe sie angehören.
Isolierter Benutzer
Ein einzelner Benutzer erhält diese Nachricht unabhängig davon, wie viele Geräte er derzeit verwendet.
Isolierte Gruppe
Nur Clients, die einer bestimmten Gruppe angehören, erhalten diese Nachricht.
Clients und die HubConnection
-Klasse
Die HubConnection
-Klasse ist ein SignalR-Clientkonzept, das für die Verbindung des Clients mit dem Hub
des Servers steht. Sie ist im Microsoft.AspNetCore.SignalR.Client
-Namespace definiert und Teil des NuGet-Pakets Microsoft.AspNetCore.SignalR.Client.
Sie erstellen ein HubConnection
, indem Sie das Generatormuster und den entsprechenden HubConnectionBuilder
-Typ verwenden. Anhand der Route (oder des System.Uri) des Hubs kann eine HubConnection
erstellt werden. Der Generator kann auch zusätzliche Konfigurationsoptionen angeben, darunter die Protokollierung, das gewünschte Protokoll, die Weiterleitung des Authentifizierungstokens und die automatische Wiederverbindung, um nur einige zu nennen.
Über die HubConnection
-API werden Funktionen zum Starten und Beenden verfügbar gemacht, mit denen die Verbindung mit dem Server gestartet bzw. beendet werden kann. Darüber hinaus sind Funktionen zum Streamen, Aufrufen von Hubmethoden und Abonnieren von Ereignissen vorhanden.
Beispiel für die Erstellung eines HubConnection
-Objekts
Um ein HubConnection
-Objekt über das .NET SignalR-Client-SDK zu erstellen, verwenden Sie den Typ 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;
}
}
}
Aufrufen von Hubmethoden
Wenn ein Client eine erfolgreich gestartete HubConnection
-Instanz erhält, kann der Client über die Erweiterungen InvokeAsync oder SendAsync-Methoden auf einem Hub aufrufen. Wenn die Hubmethode ein Task<TResult>
zurückgibt, weist das Ergebnis von InvokeAsync<TResult>
den Typ TResult
auf. Gibt die Hubmethode Task
zurück, ist kein Ergebnis vorhanden. Beide InvokeAsync
und SendAsync
erfordern den Namen der Hub-Methode und null bis 10 Parameter.
- InvokeAsync: Ruft eine Hubmethode auf dem Server auf, indem der angegebene Methodenname und optionale Argumente verwendet werden.
- SendAsync: Ruft eine Hubmethode auf dem Server auf, indem der angegebene Methodenname und optionale Argumente verwendet werden. Diese Methode wartet nicht auf eine Antwort des Empfängers.
Beispiel für den Aufruf einer Hubmethode
Wenn SendNotificationAsync
der vorherigen Consumer
-Klasse eine Methode hinzufügt, delegiert SendNotificationAsync
an _hubConnection
und ruft die NotifyAll
-Methode im Hub des Servers auf, je nach Notification
-Instanz.
public Task SendNotificationAsync(string text) =>
_hubConnection.InvokeAsync(
"NotifyAll", new Notification(text, DateTime.UtcNow));
Behandeln von Ereignissen
Für die Verarbeitung von Ereignissen registrieren Sie einen Handler bei der HubConnection
-Instanz. Rufen Sie eine der HubConnectionExtensions.On-Überladungen auf, wenn Sie den Namen der Hubmethode kennen und über null bis acht Parameter verfügen. Mit dem Handler können alle folgenden Action
-Varianten abgedeckt werden:
- 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>
Alternativ können Sie die asynchronen Handler-APIs Func<TResult>
verwenden, wobei TResult
für eine Task
-Variante steht:
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>
Das Ergebnis der Registrierung eines Ereignishandlers ist IDisposable
, was als Abonnement dient. Rufen Sie Dispose auf, um das Abonnement für den Handler zu kündigen.
Beispiel für eine Ereignisregistrierung
Zur Aktualisierung der obigen Consumer
-Klasse führen Sie die Registrierung bei einem Ereignis durch, indem Sie einen Handler angeben und On
aufrufen:
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.
}
Die OnNotificationReceivedAsync
-Methode wird aufgerufen, wenn von der Hubinstanz des Servers das Ereignis "NotificationReceived"
ausgelöst wird.
Aktualisierungen für Contoso Pizza-Livebestellungen
Der Servercode für die Webanwendung muss über eine Hub
-Implementierung verfügen und eine Route zu Clients verfügbar machen. Für Hub
kann der eindeutige Bezeichner des Bestellobjekts verwendet werden, um eine Gruppe für die Nachverfolgung zu erstellen. Alle Aktualisierungen in Bezug auf Änderungen des Bestellstatus können dann in dieser Gruppe kommuniziert werden.
Der Clientcode muss ebenfalls aktualisiert werden, um anzugeben, dass die Contoso Pizza-Anwendung eine Blazor WebAssembly-App ist. Sie können entweder das JavaScript- oder das .NET-Client-SDK verwenden. Anschließend ersetzen Sie die Funktion für clientseitige Abrufe durch Code, mit dem ein HubConnection
-Objekt erstellt wird, und starten die Verbindung mit dem Server. Bei der Navigation zur Seite der Auftragsverfolgung müsste der Code der spezifischen Gruppe des Auftrags beitreten, an die die Änderungsaktualisierungen gesendet werden. Sie abonnieren das Ereignis für Änderungen des Auftragsstatus und behandeln es dann entsprechend.