Funktionsweise von ASP.NET Core SignalR

Abgeschlossen

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:

  • Hub: Ein Standardhub.
  • Hub<T>: Ein stark typisierter generischer Hub.

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 und T 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 und Task<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

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

    Alle verbundenen Clients erhalten diese Nachricht unabhängig davon, welcher Gruppe sie angehören.

  • Isolierter Benutzer

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

    Ein einzelner Benutzer erhält diese Nachricht unabhängig davon, wie viele Geräte er derzeit verwendet.

  • Isolierte Gruppe

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

    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:

Alternativ können Sie die asynchronen Handler-APIs Func<TResult> verwenden, wobei TResult für eine Task-Variante steht:

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.