Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
Von Rachel Appel und Kevin Griffin
Die SignalR Hubs-API ermöglicht es verbundenen Clients, Methoden auf dem Server aufzurufen, wodurch die Kommunikation in Echtzeit erleichtert wird. Der Server definiert Methoden, die vom Client aufgerufen werden, und der Client definiert Methoden, die vom Server aufgerufen werden. SignalR ermöglicht außerdem die indirekte Client-zu-Client-Kommunikation, bei der der SignalR Hub die Vermittlung bereitstellt. Dieser Ansatz ermöglicht das Senden von Nachrichten zwischen einzelnen Clients, Gruppen oder an alle verbundenen Clients. SignalR kümmert sich um alles, was erforderlich ist, um die Kommunikation zwischen Client und Server sowie zwischen Server und Client in Echtzeit zu ermöglichen.
In diesem Artikel wird beschrieben, wie Hubs konfiguriert, Nachrichten an Clients gesendet und Server Ergebnisse von Clients verarbeiten können.
Konfigurieren von SignalR-Hubs
Registrieren Sie die für SignalR-Hubs erforderlichen Dienste, indem Sie die Methode AddSignalR in der Datei Program.cs aufrufen:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddSignalR();
Konfigurieren Sie SignalR Endpunkte, indem Sie die MapHub Methode in der datei Program.cs aufrufen:
app.MapRazorPages();
app.MapHub<ChatHub>("/Chat");
app.Run();
Note
Serverseitige ASP.NET Core SignalR-Assemblys werden jetzt mit dem .NET Core SDK installiert. Weitere Informationen finden Sie unter SignalR Assemblies im gemeinsam genutzten Framework.
Erstellen und Verwenden von Hubs
Erstellen Sie einen Hub, indem Sie eine Klasse deklarieren, die von Hub erbt. Fügen Sie der Klasse public-Methoden hinzu, um sie von Clients aus aufrufbar zu machen:
public class ChatHub : Hub
{
public async Task SendMessage(string user, string message)
=> await Clients.All.SendAsync("ReceiveMessage", user, message);
}
Note
Hubs sind vorübergehende Objekte:
- Speichern Sie den Zustand nicht in einer Eigenschaft der Hubklasse. Jeder Hubmethodenaufruf wird in einer neuen Hubinstanz ausgeführt.
- Instanziieren Sie einen Hub nicht direkt über Abhängigkeitsinjektion. Wenn Sie Nachrichten von einer anderen Stelle in Ihrer Anwendung an einen Client senden möchten, verwenden Sie einen IHubContext.
- Verwenden Sie
awaitbeim Aufrufen asynchroner Methoden, die davon abhängen, dass der Hub aktiv bleibt. Wenn Sie beispielsweise eine Methode wieClients.All.SendAsync(...)aufrufen, ohneawaitzu verwenden, kann der Aufruf fehlschlagen, und die Hubmethode wird abgeschlossen, bevorSendAsyncabgeschlossen ist.
Note
Hub-Methodenparameter, Rückgabewerte und Datenstromelemente können C#-Union-Typen nur mit der Standardeinstellung JsonHubProtocol sein. Die MessagePack- und Newtonsoft.Json-Hubprotokolle unterstützen keine Gewerkschaften.
Verwenden von 'Context'-Objekteigenschaften und -methoden
Die Hub-Klasse enthält eine Context-Eigenschaft, die die folgenden Eigenschaften mit Informationen zur Verbindung enthält:
| Property | Description |
|---|---|
| ConnectionId | Ruft die eindeutige ID für die Verbindung ab, die von SignalR zugewiesen wird. Für jede Verbindung gibt es eine Verbindungs-ID. |
| UserIdentifier | Ruft den Benutzerbezeichner ab. Standardmäßig verwendet SignalR die Eigenschaft ClaimTypes.NameIdentifier des der Verbindung zugeordneten ClaimsPrincipal als Benutzerkennung. |
| User | Ruft den ClaimsPrincipal ab, der dem aktuellen Benutzer zugeordnet ist. |
| Items | Ruft eine Schlüssel-Wert-Sammlung ab, die zum Freigeben von Daten innerhalb des Bereichs dieser Verbindung verwendet werden kann. Daten können in dieser Sammlung gespeichert werden und bleiben für die Dauer der Verbindung zwischen verschiedenen Hubmethodenaufrufen erhalten. |
| Features | Ruft die Sammlung der Features ab, die für die Verbindung verfügbar sind. Diese Sammlung ist derzeit in den meisten Szenarien nicht erforderlich, daher ist eine detaillierte Dokumentation noch nicht verfügbar. |
| ConnectionAborted | Ruft ein CancellationToken ab, das eine Benachrichtigung sendet, wenn die Verbindung abgebrochen wird. |
Die Hub.Context Eigenschaft enthält auch die folgenden Methoden:
| Method | Description |
|---|---|
| GetHttpContext | Gibt den HttpContext für die Verbindung zurück, oder null, wenn die Verbindung keiner HTTP-Anforderung zugeordnet ist. Verwenden Sie für HTTP-Verbindungen diese Methode, um Informationen wie HTTP-Header und Abfragezeichenfolgen abzurufen. |
| Abort | Bricht die Verbindung ab. |
Verwenden von 'Clients'-Objekteigenschaften und -methoden
Die Hub-Klasse enthält eine Clients-Eigenschaft, die die folgenden Eigenschaften für die Kommunikation zwischen Server und Client enthält:
| Property | Description |
|---|---|
| All | Ruft eine Methode für alle verbundenen Clients auf. |
| Caller | Ruft eine Methode auf dem Client auf, der die Hubmethode aufgerufen hat. |
| Others | Ruft eine Methode für alle verbundenen Clients mit Ausnahme des Clients auf, der die Methode aufgerufen hat. |
Die Hub.Clients Eigenschaft enthält auch die folgenden Methoden:
| Method | Description |
|---|---|
| AllExcept | Ruft eine Methode für alle verbundenen Clients mit Ausnahme der angegebenen Verbindungen auf. |
| Client | Ruft eine Methode für einen bestimmten verbundenen Client auf. |
| Clients | Ruft eine Methode für bestimmte verbundene Clients auf. |
| Group | Ruft eine Methode für alle Verbindungen in der angegebenen Gruppe auf. |
| GroupExcept | Ruft eine Methode für alle Verbindungen in der angegebenen Gruppe auf, mit Ausnahme der angegebenen Verbindungen. |
| Groups | Ruft eine Methode für mehrere Gruppen von Verbindungen auf. |
| OthersInGroup | Ruft eine Methode für eine Gruppe von Verbindungen auf, mit Ausnahme des Clients, der die Hubmethode aufgerufen hat. |
| User | Ruft eine Methode für alle Verbindungen auf, die einem bestimmten Benutzer zugeordnet sind. |
| Users | Ruft eine Methode für alle Verbindungen auf, die den angegebenen Benutzern zugeordnet sind. |
Jede Eigenschaft oder Methode gibt ein Objekt mit einer SendAsync Methode zurück. Die SendAsync-Methode empfängt den Namen der aufzurufenden Clientmethode und alle Parameter.
Das von den Client und Caller-Methoden zurückgegebene Objekt enthält auch eine InvokeAsync-Methode, die verwendet werden kann, um auf ein Ergebnis vom Client zu warten.
Senden von Nachrichten an Clients
Verwenden Sie die Eigenschaften des Clients-Objekts, um Aufrufe für bestimmte Clients auszuführen. Im folgenden Beispiel gibt es drei Hubmethoden:
- Die
SendMessageMethode sendet eine Nachricht an alle verbundenen Clients mithilfe derClients.AllEigenschaft. - Die
SendMessageToCallerMethode sendet eine Nachricht mithilfe derClients.CallerEigenschaft an den Aufrufer zurück. - Die
SendMessageToGroupMethode sendet eine Nachricht an alle Clients in derSignalR UsersGruppe.
public async Task SendMessage(string user, string message)
=> await Clients.All.SendAsync("ReceiveMessage", user, message);
public async Task SendMessageToCaller(string user, string message)
=> await Clients.Caller.SendAsync("ReceiveMessage", user, message);
public async Task SendMessageToGroup(string user, string message)
=> await Clients.Group("SignalR Users").SendAsync("ReceiveMessage", user, message);
Verwenden von stark typisierten Hubs
Ein Nachteil der Verwendung der SendAsync Methode besteht darin, dass sie auf einer Zeichenfolge basiert, um die clientbasierte Methode anzugeben, die aufgerufen werden soll. Dieser Entwurf macht den Code anfällig für Laufzeitfehler, wenn der Methodenname falsch geschrieben ist oder im Client fehlt.
Eine Alternative zur Verwendung der SendAsync Methode besteht darin, die Hub Klasse stark einzugeben mit Hub<T>. Im folgenden Beispiel wird die ChatHub Client-Methode in eine Schnittstelle namens IChatClient extrahiert:
public interface IChatClient
{
Task ReceiveMessage(string user, string message);
}
Mit der Schnittstelle lässt sich das vorangehende ChatHub-Beispiel so umzustrukturieren, dass es stark typisiert ist:
public class StronglyTypedChatHub : Hub<IChatClient>
{
public async Task SendMessage(string user, string message)
=> await Clients.All.ReceiveMessage(user, message);
public async Task SendMessageToCaller(string user, string message)
=> await Clients.Caller.ReceiveMessage(user, message);
public async Task SendMessageToGroup(string user, string message)
=> await Clients.Group("SignalR Users").ReceiveMessage(user, message);
}
Die Verwendung von Hub<IChatClient> ermöglicht die Überprüfung der Clientmethoden zur Kompilierzeit. Dieser Ansatz verhindert Probleme bei der Verwendung von Zeichenfolgen, da über Hub<T> nur auf die in der Schnittstelle definierten Methoden zugegriffen werden kann. Die Verwendung eines stark typisierten Hub<T> deaktiviert die Möglichkeit, die Methode SendAsync zu verwenden.
Note
Das Async-Suffix wird nicht aus Methodennamen entfernt. Verwenden Sie .on('MyMethodAsync') nicht als Name, es sei denn, eine Clientmethode ist mit MyMethodAsync definiert.
Anfordern von Clientergebnissen
Zusätzlich zu Aufrufen von Clients kann der Server ein Ergebnis von einem Client anfordern. In diesem Szenario verwendet der Server die ISingleClientProxy.InvokeAsync Methode, und der Client gibt ein Ergebnis aus seinem .On Handler zurück.
Es gibt zwei Möglichkeiten, die API auf dem Server zu verwenden.
Sie können in einer Client(...)-Methode Caller oder Clients für die Hub-Eigenschaft aufrufen:
public class ChatHub : Hub
{
public async Task<string> WaitForMessage(string connectionId)
{
var message = await Clients.Client(connectionId).InvokeAsync<string>(
"GetMessage");
return message;
}
}
Oder Sie können Client(...) auf einer Instanz von IHubContext<T> aufrufen:
async Task SomeMethod(IHubContext<MyHub> context)
{
string result = await context.Clients.Client(connectionID).InvokeAsync<string>(
"GetMessage");
}
Stark typierte Hubs können auch Werte aus Schnittstellenmethoden zurückgeben:
public interface IClient
{
Task<string> GetMessage();
}
public class ChatHub : Hub<IClient>
{
public async Task<string> WaitForMessage(string connectionId)
{
string message = await Clients.Client(connectionId).GetMessage();
return message;
}
}
Clients geben Ergebnisse in ihren .On(...)-Handlern zurück, wie in den folgenden Abschnitten dargestellt.
.NET-Client
hubConnection.On("GetMessage", async () =>
{
Console.WriteLine("Enter message:");
var message = await Console.In.ReadLineAsync();
return message;
});
TypeScript-Client
hubConnection.on("GetMessage", async () => {
let promise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("message");
}, 100);
});
return promise;
});
Java-Client
hubConnection.onWithResult("GetMessage", () -> {
return Single.just("message");
});
Ändern des Namens einer Hubmethode
Standardmäßig ist der Name einer Serverhubmethode der Name der .NET-Methode. Um dieses Standardverhalten für eine bestimmte Methode zu ändern, verwenden Sie das HubMethodName-Attribut. Der Client sollte diesen Namen anstelle des .NET-Methodennamens verwenden, wenn die Methode aufgerufen wird:
[HubMethodName("SendMessageToUser")]
public async Task DirectMessage(string user, string message)
=> await Clients.User(user).SendAsync("ReceiveMessage", user, message);
Einfügen von Diensten in einen Hub
Hubkonstruktoren können Dienste aus der Abhängigkeitseinfügung als Parameter akzeptieren, die in Eigenschaften der Klasse für die Verwendung in einer Hubmethode gespeichert werden können.
Wenn Sie mehrere Dienste für verschiedene Hubmethoden oder als alternative Methode zum Schreiben von Code einfügen, können Hubmethoden auch Dienste aus der Abhängigkeitseinfügung akzeptieren. Standardmäßig werden die Parameter von Hub-Methoden geprüft und, wenn möglich, über die Abhängigkeitsinjektion aufgelöst.
services.AddSingleton<IDatabaseService, DatabaseServiceImpl>();
// ...
public class ChatHub : Hub
{
public Task SendMessage(string user, string message, IDatabaseService dbService)
{
var userName = dbService.GetUserName(user);
return Clients.All.SendAsync("ReceiveMessage", userName, message);
}
}
Wenn die implizite Auflösung von Parametern von Diensten nicht gewünscht wird, können Sie das Verhalten mit der Serveroption DisableImplicitFromServicesParameters deaktivieren.
Um explizit anzugeben, welche Parameter aus der Abhängigkeitseinfügung in Hubmethoden aufgelöst werden, verwenden Sie die DisableImplicitFromServicesParameters-Eigenschaft . Geben Sie das [FromServices]-Attribut oder ein benutzerdefiniertes Attribut an, das IFromServiceMetadata implementiert, bei den Hubmethodenparametern, die per Abhängigkeitsinjektion aufgelöst werden sollen.
services.AddSingleton<IDatabaseService, DatabaseServiceImpl>();
services.AddSignalR(options =>
{
options.DisableImplicitFromServicesParameters = true;
});
// ...
public class ChatHub : Hub
{
public Task SendMessage(string user, string message,
[FromServices] IDatabaseService dbService)
{
var userName = dbService.GetUserName(user);
return Clients.All.SendAsync("ReceiveMessage", userName, message);
}
}
Note
Dieses Feature verwendet IServiceProviderIsService, die optional in Abhängigkeitseinfügungskonfigurationen implementiert ist. Wenn der Container für die Anwendungsabhängigkeitseinfügung dieses Feature nicht unterstützt, wird das Einfügen von Diensten in Hubmethoden nicht unterstützt.
Unterstützung von Schlüsseldiensten in Abhängigkeitsinjektion
Mit dem Mechanismus für schlüsselbasierte Dienste können Sie Abhängigkeitsinjektionsdienste mithilfe von Schlüsseln registrieren und abrufen. Ein Dienst ist einem Schlüssel zugeordnet, indem die AddKeyedSingleton Methode aufgerufen wird, um ihn zu registrieren. Alternativ können Sie die Methode AddKeyedScoped oder die Methode AddKeyedTransient aufrufen.
Sie greifen auf einen registrierten Dienst zu, indem Sie den Schlüssel mit dem Attribut [FromKeyedServices] angeben. Der folgende Code zeigt, wie Sie Schlüsseldienste verwenden können:
using Microsoft.AspNetCore.SignalR;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddKeyedSingleton<ICache, BigCache>("big");
builder.Services.AddKeyedSingleton<ICache, SmallCache>("small");
builder.Services.AddRazorPages();
builder.Services.AddSignalR();
var app = builder.Build();
app.MapRazorPages();
app.MapHub<MyHub>("/myHub");
app.Run();
public interface ICache
{
object Get(string key);
}
public class BigCache : ICache
{
public object Get(string key) => $"Resolving {key} from big cache.";
}
public class SmallCache : ICache
{
public object Get(string key) => $"Resolving {key} from small cache.";
}
public class MyHub : Hub
{
public void SmallCacheMethod([FromKeyedServices("small")] ICache cache)
{
Console.WriteLine(cache.Get("signalr"));
}
public void BigCacheMethod([FromKeyedServices("big")] ICache cache)
{
Console.WriteLine(cache.Get("signalr"));
}
}
Streaming-Aufrufe pro Verbindung begrenzen
MaximumParallelInvocationsPerClient steuert die Anzahl der Aufrufe von Nicht-Streaming-Hubmethoden, die ein Client parallel ausführen kann, bevor er in die Warteschlange gestellt wird. Sie gilt nicht für Aufrufe des Streaming-Hubs. Streamingaufrufe werden absichtlich ausgeschlossen, da sie voraussichtlich lang und gleichzeitig ausgeführt werden, sodass ein Client unabhängig von dieser Einstellung eine beliebige Anzahl gleichzeitiger Streams starten kann.
Um eine Begrenzung pro Verbindung für Streaming-Aufrufe zu erzwingen, kapseln Sie den Stream direkt in der Hubmethode selbst mithilfe einer privaten Hilfsfunktion, die einen Zähler erhöht, bevor Elemente bereitgestellt werden, und ihn in einem finally-Block verringert:
using System.Collections.Concurrent;
using System.Runtime.CompilerServices;
public class StreamingHub : Hub
{
private static readonly ConcurrentDictionary<string, int> _activeStreams = new();
private const int MaxConcurrentStreams = 2;
public IAsyncEnumerable<int> Counter(
int count,
int delay,
CancellationToken cancellationToken)
{
return WithLimit(Context.ConnectionId, GetCounter(count, delay, cancellationToken));
}
private async IAsyncEnumerable<int> GetCounter(
int count,
int delay,
[EnumeratorCancellation] CancellationToken cancellationToken)
{
for (var i = 0; i < count; i++)
{
cancellationToken.ThrowIfCancellationRequested();
yield return i;
await Task.Delay(delay, cancellationToken);
}
}
private async IAsyncEnumerable<T> WithLimit(
string connectionId,
IAsyncEnumerable<T> stream,
[EnumeratorCancellation] CancellationToken cancellationToken = default)
{
var current = _activeStreams.AddOrUpdate(
connectionId,
addValue: 1,
updateValueFactory: (_, count) => count + 1);
if (current > MaxConcurrentStreams)
{
Decrement(connectionId);
throw new HubException(
$"The connection is limited to {MaxConcurrentStreams} concurrent streaming invocations.");
}
try
{
await foreach (var item in stream.WithCancellation(cancellationToken))
{
yield return item;
}
}
finally
{
Decrement(connectionId);
}
}
private static void Decrement(string connectionId)
{
while (_activeStreams.TryGetValue(connectionId, out var current))
{
if (current <= 1)
{
if (_activeStreams.TryRemove(new KeyValuePair<string, int>(connectionId, current)))
{
return;
}
}
else if (_activeStreams.TryUpdate(connectionId, current - 1, current))
{
return;
}
}
}
}
Der entscheidende Punkt ist, dass WithLimit das ursprüngliche IAsyncEnumerable<T> umschließt und den Zähler für die gesamte Lebensdauer des Streams erhöht hält, nicht nur bis das erste Element zurückgegeben wird.
Der finally-Block wird nur ausgeführt, wenn der Client das Lesen des Datenstroms abgeschlossen hat, ihn abbricht oder die Verbindung unterbrochen wird.
Wenn Ihre Streaming-Hub-Methoden ChannelReader<T> anstelle von IAsyncEnumerable<T> zurückgeben, kann ein ähnlicher Wrapper verwendet werden. Es sollte dasselbe _activeStreams-Wörterbuch verwenden, sodass beide Stream-Typen dieselbe Begrenzung auf Verbindungsebene nutzen, anstatt dass jeder einen eigenen unabhängigen Zähler führt.
Note
Das _activeStreams Wörterbuch ist static, daher wird es von allen Hub-Instanzen gemeinsam genutzt. Wenn Sie den DI-verwalteten Zustand bevorzugen, registrieren Sie einen Singleton-Dienst, der das Wörterbuch besitzt, und fügen Sie ihn in den Hubkonstruktor ein.
Ereignisse für eine Verbindung verarbeiten
Die Hubs-API von SignalR stellt die virtuellen OnConnectedAsync- und OnDisconnectedAsync-Methoden zum Verwalten und Nachverfolgen von Verbindungen bereit. Überschreiben Sie die virtuelle OnConnectedAsync-Methode, um Aktionen auszuführen, wenn ein Client eine Verbindung mit dem Hub herstellt, ihn z. B. einer Gruppe hinzufügt:
public override async Task OnConnectedAsync()
{
await Groups.AddToGroupAsync(Context.ConnectionId, "SignalR Users");
await base.OnConnectedAsync();
}
Überschreiben Sie die virtuelle OnDisconnectedAsync-Methode, um Aktionen auszuführen, wenn ein Client die Verbindung trennt. Wenn der Client die Verbindung absichtlich trennt, z. B. durch Aufrufen von connection.stop(), wird der exception-Parameter auf null festgelegt. Wenn der Client jedoch aufgrund eines Fehlers (z. B. eines Netzwerkfehlers) die Verbindung trennt, enthält der exception-Parameter eine Ausnahme, die den Fehler beschreibt:
public override async Task OnDisconnectedAsync(Exception? exception)
{
await base.OnDisconnectedAsync(exception);
}
Die RemoveFromGroupAsync Methode muss nicht innerhalb der OnDisconnectedAsync Methode aufgerufen werden, da sie automatisch behandelt wird.
Fehler behandeln
Ausnahmen, die in Hubmethoden ausgelöst werden, werden an den Client gesendet, der die Methode aufgerufen hat. Auf dem JavaScript-Client gibt die invoke Methode ein JavaScript-Objekt "Promise" zurück. Clients können einen catch-Handler an die zurückgegebene Zusage anfügen oder try/catch mit async/await verwenden, um Ausnahmen zu behandeln:
try {
await connection.invoke("SendMessage", user, message);
} catch (err) {
console.error(err);
}
Verbindungen werden nicht geschlossen, wenn ein Hub eine Ausnahme auslöst. SignalR gibt standardmäßig eine generische Fehlermeldung an den Client zurück, wie im folgenden Beispiel gezeigt:
Microsoft.AspNetCore.SignalR.HubException: An unexpected error occurred invoking 'SendMessage' on the server.
Unerwartete Ausnahmen enthalten häufig vertrauliche Informationen, z. B. den Namen eines Datenbankservers in einer Ausnahme, die ausgelöst wird, wenn die Datenbankverbindung fehlschlägt. Als Sicherheitsmaßnahme SignalR werden diese detaillierten Fehlermeldungen standardmäßig nicht verfügbar gemacht. Weitere Informationen dazu, warum Ausnahmedetails unterdrückt werden, finden Sie unter Sicherheitsüberlegungen in ASP.NET Core SignalR.
Wenn eine Ausnahmebedingung an den Client weitergegeben werden muss, verwenden Sie die HubException-Klasse. Wenn ein HubException Ereignis in einer Hubmethode ausgelöst wird, SignalRsendet die gesamte Ausnahmemeldung an den Client in einer nicht geänderten Form:
public Task ThrowException()
=> throw new HubException("This error will be sent to the client!");
Note
SignalR sendet nur die Message-Eigenschaft der Ausnahme an den Client. Die Stapelablaufverfolgung und andere Eigenschaften der Ausnahme stehen dem Client nicht zur Verfügung.
Verwandte Inhalte
Von Rachel Appel und Kevin Griffin
Die SignalR Hubs-API ermöglicht es verbundenen Clients, Methoden auf dem Server aufzurufen, wodurch die Kommunikation in Echtzeit erleichtert wird. Der Server definiert Methoden, die vom Client aufgerufen werden, und der Client definiert Methoden, die vom Server aufgerufen werden. SignalR ermöglicht auch eine indirekte Kommunikation von Client zu Client, die immer durch den SignalR Hub vermittelt wird, so dass Nachrichten zwischen einzelnen Clients, Gruppen oder an alle verbundenen Clients gesendet werden können. SignalR kümmert sich um alles, was erforderlich ist, um die Kommunikation zwischen Client und Server sowie zwischen Server und Client in Echtzeit zu ermöglichen.
Konfigurieren von SignalR-Hubs
Rufen Sie zum Registrieren der für SignalR-Hubs erforderlichen Dienste AddSignalR in Program.cs auf:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddSignalR();
Rufen Sie SignalR auf, um MapHub-Endpunkte zu konfigurieren, auch in Program.cs:
app.MapRazorPages();
app.MapHub<ChatHub>("/Chat");
app.Run();
Note
Serverseitige ASP.NET Core SignalR-Assemblys werden jetzt mit dem .NET Core SDK installiert. Weitere Informationen finden Sie unter SignalR Assemblies im gemeinsam genutzten Framework.
Erstellen und Verwenden von Hubs
Erstellen Sie einen Hub, indem Sie eine Klasse deklarieren, die von Hub erbt. Fügen Sie der Klasse public-Methoden hinzu, um sie von Clients aus aufrufbar zu machen:
public class ChatHub : Hub
{
public async Task SendMessage(string user, string message)
=> await Clients.All.SendAsync("ReceiveMessage", user, message);
}
Note
Hubs sind vorübergehende Objekte:
- Speichern Sie den Zustand nicht in einer Eigenschaft der Hubklasse. Jeder Hubmethodenaufruf wird in einer neuen Hubinstanz ausgeführt.
- Instanziieren Sie einen Hub nicht direkt über Abhängigkeitsinjektion. Um Nachrichten von einer anderen Stelle in Ihrer Anwendung an einen Client zu senden, verwenden Sie
IHubContext. - Verwenden Sie
awaitbeim Aufrufen asynchroner Methoden, die davon abhängen, dass der Hub aktiv bleibt. Eine Methode wieClients.All.SendAsync(...)kann beispielsweise fehlschlagen, wenn sie ohneawaitaufgerufen wird und die Hubmethode abgeschlossen wird, bevorSendAsyncabgeschlossen ist.
Das Context-Objekt
Die Hub-Klasse enthält eine Context-Eigenschaft, die die folgenden Eigenschaften mit Informationen zur Verbindung enthält:
| Property | Description |
|---|---|
| ConnectionId | Ruft die eindeutige ID für die Verbindung ab, die von SignalR zugewiesen wird. Für jede Verbindung gibt es eine Verbindungs-ID. |
| UserIdentifier | Ruft den Benutzerbezeichner ab. SignalR verwendet standardmäßig den ClaimTypes.NameIdentifier von ClaimsPrincipal, der der Verbindung zugeordnet ist, als Benutzerbezeichner. |
| User | Ruft den ClaimsPrincipal ab, der dem aktuellen Benutzer zugeordnet ist. |
| Items | Ruft eine Schlüssel-Wert-Sammlung ab, die zum Freigeben von Daten innerhalb des Bereichs dieser Verbindung verwendet werden kann. Daten können in dieser Sammlung gespeichert werden und bleiben für die Verbindung über verschiedene Hubmethodenaufrufe hinweg bestehen. |
| Features | Ruft die Sammlung der Features ab, die für die Verbindung verfügbar sind. Derzeit ist diese Sammlung in den meisten Szenarien nicht erforderlich, daher wurde sie noch nicht ausführlich dokumentiert. |
| ConnectionAborted | Ruft ein CancellationToken ab, das eine Benachrichtigung sendet, wenn die Verbindung abgebrochen wird. |
Hub.Context enthält auch die folgenden Methoden:
| Method | Description |
|---|---|
| GetHttpContext | Gibt den HttpContext für die Verbindung zurück, oder null, wenn die Verbindung keiner HTTP-Anforderung zugeordnet ist. Verwenden Sie für HTTP-Verbindungen diese Methode, um Informationen wie HTTP-Header und Abfragezeichenfolgen abzurufen. |
| Abort | Bricht die Verbindung ab. |
Das Clients-Objekt
Die Hub-Klasse enthält eine Clients-Eigenschaft, die die folgenden Eigenschaften für die Kommunikation zwischen Server und Client enthält:
| Property | Description |
|---|---|
| All | Ruft eine Methode auf allen verbundenen Clients auf. |
| Caller | Ruft eine Methode auf dem Client auf, die die Hubmethode aufgerufen hat |
| Others | Ruft eine Methode auf allen verbundenen Clients mit Ausnahme des Clients auf, der die Methode aufgerufen hat. |
Hub.Clients enthält auch die folgenden Methoden:
| Method | Description |
|---|---|
| AllExcept | Ruft eine Methode auf allen verbundenen Clients mit Ausnahme der angegebenen Verbindungen auf. |
| Client | Ruft eine Methode auf einem bestimmten verbundenen Client auf. |
| Clients | Ruft eine Methode bei bestimmten verbundenen Clients auf. |
| Group | Ruft eine Methode für alle Verbindungen in der angegebenen Gruppe auf. |
| GroupExcept | Ruft eine Methode für alle Verbindungen in der angegebenen Gruppe mit Ausnahme der angegebenen Verbindungen auf. |
| Groups | Ruft eine Methode für mehrere Gruppen von Verbindungen auf. |
| OthersInGroup | Ruft eine Methode für eine Gruppe von Verbindungen auf, wobei der Client, der die Hubmethode aufgerufen hat, ausgeschlossen wird. |
| User | Ruft eine Methode für alle Verbindungen auf, die einem bestimmten Benutzer zugeordnet sind. |
| Users | Ruft eine Methode für alle Verbindungen auf, die den angegebenen Benutzern zugeordnet sind. |
Jede Eigenschaft oder Methode in den vorherigen Tabellen gibt ein Objekt mit einer SendAsync-Methode zurück. Die SendAsync-Methode empfängt den Namen der aufzurufenden Clientmethode und alle Parameter.
Das von den Client und Caller-Methoden zurückgegebene Objekt enthält auch eine InvokeAsync-Methode, die verwendet werden kann, um auf ein Ergebnis vom Client zu warten.
Senden von Nachrichten an Clients
Verwenden Sie die Eigenschaften des Clients-Objekts, um Aufrufe für bestimmte Clients auszuführen. Im folgenden Beispiel gibt es drei Hubmethoden:
-
SendMessagesendet mithilfe vonClients.Alleine Nachricht an alle verbundenen Clients . -
SendMessageToCallersendet mithilfe vonClients.Callereine Nachricht zurück an den Aufrufer. -
SendMessageToGroupsendet eine Nachricht an alle Clients in derSignalR Users-Gruppe.
public async Task SendMessage(string user, string message)
=> await Clients.All.SendAsync("ReceiveMessage", user, message);
public async Task SendMessageToCaller(string user, string message)
=> await Clients.Caller.SendAsync("ReceiveMessage", user, message);
public async Task SendMessageToGroup(string user, string message)
=> await Clients.Group("SignalR Users").SendAsync("ReceiveMessage", user, message);
Stark typisierte Hubs
Ein Nachteil der Verwendung von SendAsync besteht darin, dass eine Zeichenfolge erforderlich ist, um die Clientmethode anzugeben, die aufgerufen werden soll. Dadurch kann es zu Laufzeitfehlern kommen, wenn der Methodenname falsch geschrieben ist oder im Client fehlt.
Eine Alternative zur Verwendung von SendAsync besteht darin, die Hub-Klasse mit Hub<T> stark zu typisieren. Im folgenden Beispiel wurde die ChatHub-Clientmethode in eine Schnittstelle namens IChatClient extrahiert:
public interface IChatClient
{
Task ReceiveMessage(string user, string message);
}
Diese Schnittstelle kann verwendet werden, um das vorherige ChatHub-Beispiel so umzugestalten, dass es stark typisiert ist:
public class StronglyTypedChatHub : Hub<IChatClient>
{
public async Task SendMessage(string user, string message)
=> await Clients.All.ReceiveMessage(user, message);
public async Task SendMessageToCaller(string user, string message)
=> await Clients.Caller.ReceiveMessage(user, message);
public async Task SendMessageToGroup(string user, string message)
=> await Clients.Group("SignalR Users").ReceiveMessage(user, message);
}
Die Verwendung von Hub<IChatClient> ermöglicht die Überprüfung der Clientmethoden zur Kompilierzeit. Dadurch werden Probleme verhindert, die durch die Verwendung von Zeichenfolgen verursacht werden, weil Hub<T> nur Zugriff auf die in der Schnittstelle definierten Methoden bereitstellen kann. Die Verwendung eines stark typisierten Hub<T> deaktiviert die Möglichkeit, SendAsync zu verwenden.
Note
Das Async-Suffix wird nicht aus Methodennamen entfernt. Verwenden Sie .on('MyMethodAsync') nicht als Name, es sei denn, eine Clientmethode ist mit MyMethodAsync definiert.
Clientergebnisse
Zusätzlich zu Aufrufen von Clients kann der Server ein Ergebnis von einem Client anfordern. Dazu muss der Server ISingleClientProxy.InvokeAsync verwenden, und der Client muss ein Ergebnis aus seinem .On-Handler zurückzugeben.
Es gibt zwei Möglichkeiten, die API auf dem Server zu verwenden: Die erste besteht darin, Client(...) oder Caller für die Clients-Eigenschaft in einer Hub-Methode aufzurufen:
public class ChatHub : Hub
{
public async Task<string> WaitForMessage(string connectionId)
{
var message = await Clients.Client(connectionId).InvokeAsync<string>(
"GetMessage");
return message;
}
}
Die zweite Möglichkeit besteht darin, Client(...) für eine Instanz von IHubContext<T> aufzurufen:
async Task SomeMethod(IHubContext<MyHub> context)
{
string result = await context.Clients.Client(connectionID).InvokeAsync<string>(
"GetMessage");
}
Stark typisierte Hubs können auch Werte aus Schnittstellenmethoden zurückgeben.
public interface IClient
{
Task<string> GetMessage();
}
public class ChatHub : Hub<IClient>
{
public async Task<string> WaitForMessage(string connectionId)
{
string message = await Clients.Client(connectionId).GetMessage();
return message;
}
}
Clients geben Ergebnisse in ihren .On(...)-Handlern zurück, wie unten gezeigt:
.NET-Client
hubConnection.On("GetMessage", async () =>
{
Console.WriteLine("Enter message:");
var message = await Console.In.ReadLineAsync();
return message;
});
Typescript-Client
hubConnection.on("GetMessage", async () => {
let promise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("message");
}, 100);
});
return promise;
});
Java-Client
hubConnection.onWithResult("GetMessage", () -> {
return Single.just("message");
});
Ändern des Namens einer Hubmethode
Standardmäßig ist der Name einer Serverhubmethode der Name der .NET-Methode. Um dieses Standardverhalten für eine bestimmte Methode zu ändern, verwenden Sie das HubMethodName-Attribut. Der Client sollte diesen Namen anstelle des .NET-Methodennamens verwenden, wenn die Methode aufgerufen wird:
[HubMethodName("SendMessageToUser")]
public async Task DirectMessage(string user, string message)
=> await Clients.User(user).SendAsync("ReceiveMessage", user, message);
Einfügen von Diensten in einen Hub
Hubkonstruktoren können Dienste der Abhängigkeitsinjektion als Parameter akzeptieren, die in Eigenschaften der Klasse zur Verwendung in einer Hubmethode gespeichert werden können.
Beim Einfügen mehrerer Dienste für verschiedene Hubmethoden oder als alternatives Verfahren zum Schreiben von Code können Hubmethoden auch Dienste von DI akzeptieren. Standardmäßig werden Hubmethodenparameter überprüft und nach Möglichkeit von DI aufgelöst.
services.AddSingleton<IDatabaseService, DatabaseServiceImpl>();
// ...
public class ChatHub : Hub
{
public Task SendMessage(string user, string message, IDatabaseService dbService)
{
var userName = dbService.GetUserName(user);
return Clients.All.SendAsync("ReceiveMessage", userName, message);
}
}
Wenn die implizite Auflösung von Parametern aus Diensten nicht gewünscht ist, deaktivieren Sie sie mit DisableImplicitFromServicesParameters.
Um explizit anzugeben, welche Parameter in Hubmethoden von DI aufgelöst werden, verwenden Sie die Option DisableImplicitFromServicesParameters und das Attribut [FromServices] oder ein benutzerdefiniertes Attribut, das IFromServiceMetadata implementiert, für die Parameter der Hubmethode, die von DI aufgelöst werden sollen.
services.AddSingleton<IDatabaseService, DatabaseServiceImpl>();
services.AddSignalR(options =>
{
options.DisableImplicitFromServicesParameters = true;
});
// ...
public class ChatHub : Hub
{
public Task SendMessage(string user, string message,
[FromServices] IDatabaseService dbService)
{
var userName = dbService.GetUserName(user);
return Clients.All.SendAsync("ReceiveMessage", userName, message);
}
}
Note
Dieses Feature verwendet das IServiceProviderIsService-Element, das optional von DI-Implementierungen implementiert wird. Wenn der DI-Container der App dieses Feature nicht unterstützt, wird das Einfügen von Diensten in Hubmethoden nicht unterstützt.
Ereignisse für eine Verbindung verarbeiten
Die Hubs-API von SignalR stellt die virtuellen OnConnectedAsync- und OnDisconnectedAsync-Methoden zum Verwalten und Nachverfolgen von Verbindungen bereit. Überschreiben Sie die virtuelle OnConnectedAsync-Methode, um Aktionen auszuführen, wenn ein Client eine Verbindung mit dem Hub herstellt, ihn z. B. einer Gruppe hinzufügt:
public override async Task OnConnectedAsync()
{
await Groups.AddToGroupAsync(Context.ConnectionId, "SignalR Users");
await base.OnConnectedAsync();
}
Überschreiben Sie die virtuelle OnDisconnectedAsync-Methode, um Aktionen auszuführen, wenn ein Client die Verbindung trennt. Wenn der Client die Verbindung absichtlich trennt, z. B. durch Aufrufen von connection.stop(), wird der exception-Parameter auf null festgelegt. Wenn der Client jedoch aufgrund eines Fehlers (z. B. eines Netzwerkfehlers) die Verbindung trennt, enthält der exception-Parameter eine Ausnahme, die den Fehler beschreibt:
public override async Task OnDisconnectedAsync(Exception? exception)
{
await base.OnDisconnectedAsync(exception);
}
RemoveFromGroupAsync muss nicht in OnDisconnectedAsync aufgerufen werden, das Element wird automatisch für Sie verarbeitet.
Fehler behandeln
Ausnahmen, die in Hubmethoden ausgelöst werden, werden an den Client gesendet, der die Methode aufgerufen hat. Auf dem JavaScript-Client gibt die invoke-Methode eine JavaScript-Promise zurück. Clients können einen catch-Handler an die zurückgegebene Zusage anfügen oder try/catch mit async/await verwenden, um Ausnahmen zu behandeln:
try {
await connection.invoke("SendMessage", user, message);
} catch (err) {
console.error(err);
}
Verbindungen werden nicht geschlossen, wenn ein Hub eine Ausnahme auslöst. SignalR gibt standardmäßig eine generische Fehlermeldung an den Client zurück, wie im folgenden Beispiel gezeigt:
Microsoft.AspNetCore.SignalR.HubException: An unexpected error occurred invoking 'SendMessage' on the server.
Unerwartete Ausnahmen enthalten häufig vertrauliche Informationen, z. B. den Namen eines Datenbankservers in einer Ausnahme, die ausgelöst wird, wenn die Datenbankverbindung fehlschlägt. SignalR stellt diese detaillierten Fehlermeldungen als Sicherheitsmaßnahme standardmäßig nicht zur Verfügung. Weitere Informationen dazu, warum Ausnahmedetails unterdrückt werden, finden Sie unter Sicherheitsüberlegungen in ASP.NET Core SignalR.
Wenn eine Ausnahmebedingung an den Client weitergegeben werden muss, verwenden Sie die HubException-Klasse. Wenn eine HubException in einer Hubmethode ausgelöst wird, SignalRsendet die gesamte Ausnahmemeldung an den Client (unverändert):
public Task ThrowException()
=> throw new HubException("This error will be sent to the client!");
Note
SignalR sendet nur die Message-Eigenschaft der Ausnahme an den Client. Die Stapelablaufverfolgung und andere Eigenschaften der Ausnahme stehen dem Client nicht zur Verfügung.
Weitere Ressourcen
Von Rachel Appel und Kevin Griffin
Die SignalR Hubs-API ermöglicht es verbundenen Clients, Methoden auf dem Server aufzurufen, wodurch die Kommunikation in Echtzeit erleichtert wird. Der Server definiert Methoden, die vom Client aufgerufen werden, und der Client definiert Methoden, die vom Server aufgerufen werden. SignalR ermöglicht auch eine indirekte Kommunikation von Client zu Client, die immer durch den SignalR Hub vermittelt wird, so dass Nachrichten zwischen einzelnen Clients, Gruppen oder an alle verbundenen Clients gesendet werden können. SignalR kümmert sich um alles, was erforderlich ist, um die Kommunikation zwischen Client und Server sowie zwischen Server und Client in Echtzeit zu ermöglichen.
Konfigurieren von SignalR-Hubs
Rufen Sie zum Registrieren der für SignalR-Hubs erforderlichen Dienste AddSignalR in Program.cs auf:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddSignalR();
Rufen Sie SignalR auf, um MapHub-Endpunkte zu konfigurieren, auch in Program.cs:
app.MapRazorPages();
app.MapHub<ChatHub>("/Chat");
app.Run();
Note
Serverseitige ASP.NET Core SignalR-Assemblys werden jetzt mit dem .NET Core SDK installiert. Weitere Informationen finden Sie unter SignalR Assemblies im gemeinsam genutzten Framework.
Erstellen und Verwenden von Hubs
Erstellen Sie einen Hub, indem Sie eine Klasse deklarieren, die von Hub erbt. Fügen Sie der Klasse public-Methoden hinzu, um sie von Clients aus aufrufbar zu machen:
public class ChatHub : Hub
{
public async Task SendMessage(string user, string message)
=> await Clients.All.SendAsync("ReceiveMessage", user, message);
}
Note
Hubs sind vorübergehende Objekte:
- Speichern Sie den Zustand nicht in einer Eigenschaft der Hubklasse. Jeder Hubmethodenaufruf wird in einer neuen Hubinstanz ausgeführt.
- Instanziieren Sie einen Hub nicht direkt über Abhängigkeitsinjektion. Um Nachrichten von einer anderen Stelle in Ihrer Anwendung an einen Client zu senden, verwenden Sie
IHubContext. - Verwenden Sie
awaitbeim Aufrufen asynchroner Methoden, die davon abhängen, dass der Hub aktiv bleibt. Eine Methode wieClients.All.SendAsync(...)kann beispielsweise fehlschlagen, wenn sie ohneawaitaufgerufen wird und die Hubmethode abgeschlossen wird, bevorSendAsyncabgeschlossen ist.
Das Context-Objekt
Die Hub-Klasse enthält eine Context-Eigenschaft, die die folgenden Eigenschaften mit Informationen zur Verbindung enthält:
| Property | Description |
|---|---|
| ConnectionId | Ruft die eindeutige ID für die Verbindung ab, die von SignalR zugewiesen wird. Für jede Verbindung gibt es eine Verbindungs-ID. |
| UserIdentifier | Ruft den Benutzerbezeichner ab. SignalR verwendet standardmäßig den ClaimTypes.NameIdentifier von ClaimsPrincipal, der der Verbindung zugeordnet ist, als Benutzerbezeichner. |
| User | Ruft den ClaimsPrincipal ab, der dem aktuellen Benutzer zugeordnet ist. |
| Items | Ruft eine Schlüssel-Wert-Sammlung ab, die zum Freigeben von Daten innerhalb des Bereichs dieser Verbindung verwendet werden kann. Daten können in dieser Sammlung gespeichert werden und bleiben für die Verbindung über verschiedene Hubmethodenaufrufe hinweg bestehen. |
| Features | Ruft die Sammlung der Features ab, die für die Verbindung verfügbar sind. Derzeit ist diese Sammlung in den meisten Szenarien nicht erforderlich, daher wurde sie noch nicht ausführlich dokumentiert. |
| ConnectionAborted | Ruft ein CancellationToken ab, das eine Benachrichtigung sendet, wenn die Verbindung abgebrochen wird. |
Hub.Context enthält auch die folgenden Methoden:
| Method | Description |
|---|---|
| GetHttpContext | Gibt den HttpContext für die Verbindung zurück, oder null, wenn die Verbindung keiner HTTP-Anforderung zugeordnet ist. Verwenden Sie für HTTP-Verbindungen diese Methode, um Informationen wie HTTP-Header und Abfragezeichenfolgen abzurufen. |
| Abort | Bricht die Verbindung ab. |
Das Clients-Objekt
Die Hub-Klasse enthält eine Clients-Eigenschaft, die die folgenden Eigenschaften für die Kommunikation zwischen Server und Client enthält:
| Property | Description |
|---|---|
| All | Ruft eine Methode auf allen verbundenen Clients auf. |
| Caller | Ruft eine Methode auf dem Client auf, die die Hubmethode aufgerufen hat |
| Others | Ruft eine Methode auf allen verbundenen Clients mit Ausnahme des Clients auf, der die Methode aufgerufen hat. |
Hub.Clients enthält auch die folgenden Methoden:
| Method | Description |
|---|---|
| AllExcept | Ruft eine Methode auf allen verbundenen Clients mit Ausnahme der angegebenen Verbindungen auf. |
| Client | Ruft eine Methode auf einem bestimmten verbundenen Client auf. |
| Clients | Ruft eine Methode bei bestimmten verbundenen Clients auf. |
| Group | Ruft eine Methode für alle Verbindungen in der angegebenen Gruppe auf. |
| GroupExcept | Ruft eine Methode für alle Verbindungen in der angegebenen Gruppe mit Ausnahme der angegebenen Verbindungen auf. |
| Groups | Ruft eine Methode für mehrere Gruppen von Verbindungen auf. |
| OthersInGroup | Ruft eine Methode für eine Gruppe von Verbindungen auf, wobei der Client, der die Hubmethode aufgerufen hat, ausgeschlossen wird. |
| User | Ruft eine Methode für alle Verbindungen auf, die einem bestimmten Benutzer zugeordnet sind. |
| Users | Ruft eine Methode für alle Verbindungen auf, die den angegebenen Benutzern zugeordnet sind. |
Jede Eigenschaft oder Methode in den vorherigen Tabellen gibt ein Objekt mit einer SendAsync-Methode zurück. Die SendAsync-Methode empfängt den Namen der aufzurufenden Clientmethode und alle Parameter.
Senden von Nachrichten an Clients
Verwenden Sie die Eigenschaften des Clients-Objekts, um Aufrufe für bestimmte Clients auszuführen. Im folgenden Beispiel gibt es drei Hubmethoden:
-
SendMessagesendet mithilfe vonClients.Alleine Nachricht an alle verbundenen Clients . -
SendMessageToCallersendet mithilfe vonClients.Callereine Nachricht zurück an den Aufrufer. -
SendMessageToGroupsendet eine Nachricht an alle Clients in derSignalR Users-Gruppe.
public async Task SendMessage(string user, string message)
=> await Clients.All.SendAsync("ReceiveMessage", user, message);
public async Task SendMessageToCaller(string user, string message)
=> await Clients.Caller.SendAsync("ReceiveMessage", user, message);
public async Task SendMessageToGroup(string user, string message)
=> await Clients.Group("SignalR Users").SendAsync("ReceiveMessage", user, message);
Stark typisierte Hubs
Ein Nachteil der Verwendung von SendAsync besteht darin, dass eine Zeichenfolge erforderlich ist, um die Clientmethode anzugeben, die aufgerufen werden soll. Dadurch kann es zu Laufzeitfehlern kommen, wenn der Methodenname falsch geschrieben ist oder im Client fehlt.
Eine Alternative zur Verwendung von SendAsync besteht darin, die Hub-Klasse mit Hub<T> stark zu typisieren. Im folgenden Beispiel wurde die ChatHub-Clientmethode in eine Schnittstelle namens IChatClient extrahiert:
public interface IChatClient
{
Task ReceiveMessage(string user, string message);
}
Diese Schnittstelle kann verwendet werden, um das vorherige ChatHub-Beispiel so umzugestalten, dass es stark typisiert ist:
public class StronglyTypedChatHub : Hub<IChatClient>
{
public async Task SendMessage(string user, string message)
=> await Clients.All.ReceiveMessage(user, message);
public async Task SendMessageToCaller(string user, string message)
=> await Clients.Caller.ReceiveMessage(user, message);
public async Task SendMessageToGroup(string user, string message)
=> await Clients.Group("SignalR Users").ReceiveMessage(user, message);
}
Die Verwendung von Hub<IChatClient> ermöglicht die Überprüfung der Clientmethoden zur Kompilierzeit. Dadurch werden Probleme verhindert, die durch die Verwendung von Zeichenfolgen verursacht werden, weil Hub<T> nur Zugriff auf die in der Schnittstelle definierten Methoden bereitstellen kann. Die Verwendung eines stark typisierten Hub<T> deaktiviert die Möglichkeit, SendAsync zu verwenden.
Note
Das Async-Suffix wird nicht aus Methodennamen entfernt. Verwenden Sie .on('MyMethodAsync') nicht als Name, es sei denn, eine Clientmethode ist mit MyMethodAsync definiert.
Ändern des Namens einer Hubmethode
Standardmäßig ist der Name einer Serverhubmethode der Name der .NET-Methode. Um dieses Standardverhalten für eine bestimmte Methode zu ändern, verwenden Sie das HubMethodName-Attribut. Der Client sollte diesen Namen anstelle des .NET-Methodennamens verwenden, wenn die Methode aufgerufen wird:
[HubMethodName("SendMessageToUser")]
public async Task DirectMessage(string user, string message)
=> await Clients.User(user).SendAsync("ReceiveMessage", user, message);
Ereignisse für eine Verbindung verarbeiten
Die Hubs-API von SignalR stellt die virtuellen OnConnectedAsync- und OnDisconnectedAsync-Methoden zum Verwalten und Nachverfolgen von Verbindungen bereit. Überschreiben Sie die virtuelle OnConnectedAsync-Methode, um Aktionen auszuführen, wenn ein Client eine Verbindung mit dem Hub herstellt, ihn z. B. einer Gruppe hinzufügt:
public override async Task OnConnectedAsync()
{
await Groups.AddToGroupAsync(Context.ConnectionId, "SignalR Users");
await base.OnConnectedAsync();
}
Überschreiben Sie die virtuelle OnDisconnectedAsync-Methode, um Aktionen auszuführen, wenn ein Client die Verbindung trennt. Wenn der Client die Verbindung absichtlich trennt, z. B. durch Aufrufen von connection.stop(), wird der exception-Parameter auf null festgelegt. Wenn der Client jedoch aufgrund eines Fehlers (z. B. eines Netzwerkfehlers) die Verbindung trennt, enthält der exception-Parameter eine Ausnahme, die den Fehler beschreibt:
public override async Task OnDisconnectedAsync(Exception? exception)
{
await base.OnDisconnectedAsync(exception);
}
RemoveFromGroupAsync muss nicht in OnDisconnectedAsync aufgerufen werden, das Element wird automatisch für Sie verarbeitet.
Fehler behandeln
Ausnahmen, die in Hubmethoden ausgelöst werden, werden an den Client gesendet, der die Methode aufgerufen hat. Auf dem JavaScript-Client gibt die invoke-Methode eine JavaScript-Promise zurück. Clients können einen catch-Handler an die zurückgegebene Zusage anfügen oder try/catch mit async/await verwenden, um Ausnahmen zu behandeln:
try {
await connection.invoke("SendMessage", user, message);
} catch (err) {
console.error(err);
}
Verbindungen werden nicht geschlossen, wenn ein Hub eine Ausnahme auslöst. SignalR gibt standardmäßig eine generische Fehlermeldung an den Client zurück, wie im folgenden Beispiel gezeigt:
Microsoft.AspNetCore.SignalR.HubException: An unexpected error occurred invoking 'SendMessage' on the server.
Unerwartete Ausnahmen enthalten häufig vertrauliche Informationen, z. B. den Namen eines Datenbankservers in einer Ausnahme, die ausgelöst wird, wenn die Datenbankverbindung fehlschlägt. SignalR stellt diese detaillierten Fehlermeldungen als Sicherheitsmaßnahme standardmäßig nicht zur Verfügung. Weitere Informationen dazu, warum Ausnahmedetails unterdrückt werden, finden Sie unter Sicherheitsüberlegungen in ASP.NET Core SignalR.
Wenn eine Ausnahmebedingung an den Client weitergegeben werden muss, verwenden Sie die HubException-Klasse. Wenn eine HubException in einer Hubmethode ausgelöst wird, SignalRsendet die gesamte Ausnahmemeldung an den Client (unverändert):
public Task ThrowException()
=> throw new HubException("This error will be sent to the client!");
Note
SignalR sendet nur die Message-Eigenschaft der Ausnahme an den Client. Die Stapelablaufverfolgung und andere Eigenschaften der Ausnahme stehen dem Client nicht zur Verfügung.
Weitere Ressourcen
Von Rachel Appel und Kevin Griffin
Anzeigen oder Herunterladen von Beispielcode (Vorgehensweise zum Herunterladen)
Was ist ein SignalR-Hub?
Die SignalR Hubs-API ermöglicht es verbundenen Clients, Methoden auf dem Server aufzurufen, wodurch die Kommunikation in Echtzeit erleichtert wird. Der Server definiert Methoden, die vom Client aufgerufen werden, und der Client definiert Methoden, die vom Server aufgerufen werden. SignalR ermöglicht auch eine indirekte Kommunikation von Client zu Client, die immer durch den SignalR Hub vermittelt wird, so dass Nachrichten zwischen einzelnen Clients, Gruppen oder an alle verbundenen Clients gesendet werden können. SignalR kümmert sich um alles, was erforderlich ist, um die Kommunikation zwischen Client und Server sowie zwischen Server und Client in Echtzeit zu ermöglichen.
Konfigurieren von SignalR-Hubs
Die SignalR-Middleware erfordert einige Dienste, die durch Aufrufe von AddSignalR konfiguriert werden:
services.AddSignalR();
Wenn Sie einer ASP.NET Core-App SignalR-Funktionen hinzufügen, richten Sie SignalR-Routen ein, indem Sie MapHub im Startup.Configure-Rückruf der UseEndpoints-Methode aufrufen:
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapHub<ChatHub>("/chathub");
});
Note
Serverseitige ASP.NET Core SignalR-Assemblys werden jetzt mit dem .NET Core SDK installiert. Weitere Informationen finden Sie unter SignalR Assemblies im gemeinsam genutzten Framework.
Erstellen und Verwenden von Hubs
Erstellen Sie einen Hub, indem Sie eine Klasse deklarieren, die von Hub erbt, und fügen Sie ihr öffentliche Methoden hinzu. Clients können Methoden aufrufen, die als public definiert sind:
public class ChatHub : Hub
{
public Task SendMessage(string user, string message)
{
return Clients.All.SendAsync("ReceiveMessage", user, message);
}
}
Sie können wie in jeder C#-Methode einen Rückgabetyp und Parameter angeben, auch komplexe Typen und Arrays. SignalR behandelt die Serialisierung und Deserialisierung komplexer Objekte und Arrays in Ihren Parametern und Rückgabewerten.
Note
Hubs sind vorübergehende Objekte:
- Speichern Sie den Zustand nicht in einer Eigenschaft in der Hubklasse. Jeder Hubmethodenaufruf wird in einer neuen Hubinstanz ausgeführt.
- Instanziieren Sie einen Hub nicht direkt über Abhängigkeitsinjektion. Um Nachrichten von einer anderen Stelle in Ihrer Anwendung an einen Client zu senden, verwenden Sie
IHubContext. - Verwenden Sie
awaitbeim Aufrufen asynchroner Methoden, die davon abhängen, dass der Hub aktiv bleibt. Eine Methode wieClients.All.SendAsync(...)kann beispielsweise fehlschlagen, wenn sie ohneawaitaufgerufen wird und die Hubmethode abgeschlossen wird, bevorSendAsyncabgeschlossen ist.
Das Context-Objekt
Die Hub-Klasse verfügt über eine Context-Eigenschaft, die die folgenden Eigenschaften mit Informationen zur Verbindung enthält:
| Property | Description |
|---|---|
| ConnectionId | Ruft die eindeutige ID für die Verbindung ab, die von SignalR zugewiesen wird. Für jede Verbindung gibt es eine Verbindungs-ID. |
| UserIdentifier | Ruft den Benutzerbezeichner ab. SignalR verwendet standardmäßig den ClaimTypes.NameIdentifier von ClaimsPrincipal, der der Verbindung zugeordnet ist, als Benutzerbezeichner. |
| User | Ruft den ClaimsPrincipal ab, der dem aktuellen Benutzer zugeordnet ist. |
| Items | Ruft eine Schlüssel-Wert-Sammlung ab, die zum Freigeben von Daten innerhalb des Bereichs dieser Verbindung verwendet werden kann. Daten können in dieser Sammlung gespeichert werden und bleiben für die Verbindung über verschiedene Hubmethodenaufrufe hinweg bestehen. |
| Features | Ruft die Sammlung der Features ab, die für die Verbindung verfügbar sind. Derzeit ist diese Sammlung in den meisten Szenarien nicht erforderlich, daher wurde sie noch nicht ausführlich dokumentiert. |
| ConnectionAborted | Ruft ein CancellationToken ab, das eine Benachrichtigung sendet, wenn die Verbindung abgebrochen wird. |
Hub.Context enthält auch die folgenden Methoden:
| Method | Description |
|---|---|
| GetHttpContext | Gibt den HttpContext für die Verbindung zurück, oder null, wenn die Verbindung keiner HTTP-Anforderung zugeordnet ist. Für HTTP-Verbindungen können Sie diese Methode verwenden, um Informationen wie HTTP-Header und Abfragezeichenfolgen abzurufen. |
| Abort | Bricht die Verbindung ab. |
Das Clients-Objekt
Die Hub-Klasse verfügt über eine Clients-Eigenschaft, die die folgenden Eigenschaften für die Kommunikation zwischen Server und Client enthält:
| Property | Description |
|---|---|
| All | Ruft eine Methode auf allen verbundenen Clients auf. |
| Caller | Ruft eine Methode auf dem Client auf, die die Hubmethode aufgerufen hat |
| Others | Ruft eine Methode auf allen verbundenen Clients mit Ausnahme des Clients auf, der die Methode aufgerufen hat. |
Hub.Clients enthält auch die folgenden Methoden:
| Method | Description |
|---|---|
| AllExcept | Ruft eine Methode auf allen verbundenen Clients mit Ausnahme der angegebenen Verbindungen auf. |
| Client | Ruft eine Methode auf einem bestimmten verbundenen Client auf. |
| Clients | Ruft eine Methode bei bestimmten verbundenen Clients auf. |
| Group | Ruft eine Methode für alle Verbindungen in der angegebenen Gruppe auf. |
| GroupExcept | Ruft eine Methode für alle Verbindungen in der angegebenen Gruppe mit Ausnahme der angegebenen Verbindungen auf. |
| Groups | Ruft eine Methode für mehrere Gruppen von Verbindungen auf. |
| OthersInGroup | Ruft eine Methode für eine Gruppe von Verbindungen auf, wobei der Client, der die Hubmethode aufgerufen hat, ausgeschlossen wird. |
| User | Ruft eine Methode für alle Verbindungen auf, die einem bestimmten Benutzer zugeordnet sind. |
| Users | Ruft eine Methode für alle Verbindungen auf, die den angegebenen Benutzern zugeordnet sind. |
Jede Eigenschaft oder Methode in den vorherigen Tabellen gibt ein Objekt mit einer SendAsync-Methode zurück. Mit der SendAsync-Methode können Sie den Namen und die Parameter der Clientmethode angeben, die aufgerufen werden soll.
Senden von Nachrichten an Clients
Verwenden Sie die Eigenschaften des Clients-Objekts, um Aufrufe für bestimmte Clients auszuführen. Im folgenden Beispiel gibt es drei Hubmethoden:
-
SendMessagesendet mithilfe vonClients.Alleine Nachricht an alle verbundenen Clients . -
SendMessageToCallersendet mithilfe vonClients.Callereine Nachricht zurück an den Aufrufer. -
SendMessageToGroupsendet eine Nachricht an alle Clients in derSignalR Users-Gruppe.
public Task SendMessage(string user, string message)
{
return Clients.All.SendAsync("ReceiveMessage", user, message);
}
public Task SendMessageToCaller(string user, string message)
{
return Clients.Caller.SendAsync("ReceiveMessage", user, message);
}
public Task SendMessageToGroup(string user, string message)
{
return Clients.Group("SignalR Users").SendAsync("ReceiveMessage", user, message);
}
Stark typisierte Hubs
Ein Nachteil der Verwendung von SendAsync besteht darin, dass eine magische Zeichenfolge erforderlich ist, um die Clientmethode anzugeben, die aufgerufen werden soll. Dadurch kann es zu Laufzeitfehlern kommen, wenn der Methodenname falsch geschrieben ist oder im Client fehlt.
Eine Alternative zur Verwendung von SendAsync besteht darin, Hub stark zu typisieren mit Hub<T>. Im folgenden Beispiel wurden die ChatHub-Clientmethoden in eine Schnittstelle namens IChatClient extrahiert.
public interface IChatClient
{
Task ReceiveMessage(string user, string message);
}
Diese Schnittstelle kann verwendet werden, um das vorherige ChatHub-Beispiel umzugestalten:
public class StronglyTypedChatHub : Hub<IChatClient>
{
public async Task SendMessage(string user, string message)
{
await Clients.All.ReceiveMessage(user, message);
}
public Task SendMessageToCaller(string user, string message)
{
return Clients.Caller.ReceiveMessage(user, message);
}
}
Die Verwendung von Hub<IChatClient> ermöglicht die Überprüfung der Clientmethoden zur Kompilierzeit. Dadurch werden Probleme verhindert, die durch die Verwendung von magischen Zeichenfolgen verursacht werden, weil Hub<T> nur Zugriff auf die in der Schnittstelle definierten Methoden bereitstellen kann.
Die Verwendung eines stark typisierten Hub<T> deaktiviert die Möglichkeit, SendAsync zu verwenden. Alle Methoden, die für die Schnittstelle definiert sind, können weiterhin als asynchron definiert werden. Tatsächlich sollte jede dieser Methoden einen Task zurückgeben. Da es sich um eine Schnittstelle handelt, verwenden Sie nicht das async-Schlüsselwort. Beispiel:
public interface IClient
{
Task ClientMethod();
}
Note
Das Async-Suffix wird nicht aus dem Methodennamen entfernt. Wenn Ihre Client-Methode nicht mit .on('MyMethodAsync') definiert ist, sollten Sie nicht MyMethodAsync als Namen verwenden.
Ändern des Namens einer Hubmethode
Standardmäßig ist der Name einer Serverhubmethode der Name der .NET-Methode. Sie können jedoch das HubMethodName-Attribut verwenden, um diese Standardeinstellung zu ändern und manuell einen Namen für die Methode anzugeben. Der Client sollte diesen Namen anstelle des .NET-Methodennamens verwenden, wenn die Methode aufgerufen wird:
[HubMethodName("SendMessageToUser")]
public Task DirectMessage(string user, string message)
{
return Clients.User(user).SendAsync("ReceiveMessage", user, message);
}
Ereignisse für eine Verbindung verarbeiten
Die Hubs-API von SignalR stellt die virtuellen OnConnectedAsync- und OnDisconnectedAsync-Methoden zum Verwalten und Nachverfolgen von Verbindungen bereit. Überschreiben Sie die virtuelle OnConnectedAsync-Methode, um Aktionen auszuführen, wenn ein Client eine Verbindung mit dem Hub herstellt, ihn z. B. einer Gruppe hinzufügt:
public override async Task OnConnectedAsync()
{
await Groups.AddToGroupAsync(Context.ConnectionId, "SignalR Users");
await base.OnConnectedAsync();
}
Überschreiben Sie die virtuelle OnDisconnectedAsync-Methode, um Aktionen auszuführen, wenn ein Client die Verbindung trennt. Wenn der Client die Verbindung absichtlich trennt (z. B. durch Aufrufen von connection.stop()), lautet der exception-Parameter null. Wenn der Client jedoch aufgrund eines Fehlers getrennt wird (z. B. durch einen Netzwerkfehler), enthält der exception-Parameter eine Ausnahme, die den Fehler beschreibt:
public override async Task OnDisconnectedAsync(Exception exception)
{
await Clients.Group("SignalR Users").SendAsync("ReceiveMessage", "I", "disconnect");
await base.OnDisconnectedAsync(exception);
}
RemoveFromGroupAsync muss nicht in OnDisconnectedAsync aufgerufen werden, das Element wird automatisch für Sie verarbeitet.
Warning
Sicherheitswarnung: Die Offenlegung von ConnectionId kann zu einem böswilligen Identitätswechsel führen, wenn die Server- oder Clientversion von SignalR ASP.NET Core 2.2 oder früher ist.
Fehler behandeln
Ausnahmen, die in Ihren Hubmethoden ausgelöst werden, werden an den Client gesendet, der die Methode aufgerufen hat. Auf dem JavaScript-Client gibt die invoke-Methode eine JavaScript-Promise zurück. Wenn der Client einen Fehler mit einem an das Promise angefügten Handler unter Verwendung von catch empfängt, wird dieser aufgerufen und als JavaScript-Error-Objekt übergeben.
connection.invoke("SendMessage", user, message).catch(err => console.error(err));
Wenn Ihr Hub eine Ausnahme auslöst, werden Verbindungen nicht geschlossen. SignalR gibt standardmäßig eine generische Fehlermeldung an den Client zurück. Beispiel:
Microsoft.AspNetCore.SignalR.HubException: An unexpected error occurred invoking 'MethodName' on the server.
Unerwartete Ausnahmen enthalten häufig vertrauliche Informationen, z. B. den Namen eines Datenbankservers in einer Ausnahme, die ausgelöst wird, wenn die Datenbankverbindung fehlschlägt. SignalR stellt diese detaillierten Fehlermeldungen als Sicherheitsmaßnahme standardmäßig nicht zur Verfügung. Weitere Informationen dazu, warum Ausnahmedetails unterdrückt werden, finden Sie unter Sicherheitsüberlegungen in ASP.NET Core SignalR.
Wenn Sie eine außergewöhnliche Bedingung haben, die Sie an den Client weitergeben möchten, können Sie die HubException-Klasse verwenden. Wenn Sie eine HubException aus Ihrer Hubmethode auslösen, SignalR die gesamte Nachricht unverändert an den Client:
public Task ThrowException()
{
throw new HubException("This error will be sent to the client!");
}
Note
SignalR sendet nur die Message-Eigenschaft der Ausnahme an den Client. Die Stapelablaufverfolgung und andere Eigenschaften der Ausnahme stehen dem Client nicht zur Verfügung.
Weitere Ressourcen
Von Rachel Appel und Kevin Griffin
Anzeigen oder Herunterladen von Beispielcode (Vorgehensweise zum Herunterladen)
Was ist ein SignalR-Hub?
Die SignalR Hubs-API ermöglicht es verbundenen Clients, Methoden auf dem Server aufzurufen, wodurch die Kommunikation in Echtzeit erleichtert wird. Der Server definiert Methoden, die vom Client aufgerufen werden, und der Client definiert Methoden, die vom Server aufgerufen werden. SignalR ermöglicht auch eine indirekte Kommunikation von Client zu Client, die immer durch den SignalR Hub vermittelt wird, so dass Nachrichten zwischen einzelnen Clients, Gruppen oder an alle verbundenen Clients gesendet werden können. SignalR kümmert sich um alles, was erforderlich ist, um die Kommunikation zwischen Client und Server sowie zwischen Server und Client in Echtzeit zu ermöglichen.
Konfigurieren von SignalR-Hubs
Die SignalR-Middleware erfordert einige Dienste, die durch Aufrufe von AddSignalR konfiguriert werden:
services.AddSignalR();
Wenn Sie einer ASP.NET Core-App SignalR-Funktionen hinzufügen, richten Sie SignalR-Routen ein, indem Sie UseSignalR in der Startup.Configure-Methode aufrufen:
app.UseSignalR(route =>
{
route.MapHub<ChatHub>("/chathub");
});
Erstellen und Verwenden von Hubs
Erstellen Sie einen Hub, indem Sie eine Klasse deklarieren, die von Hub erbt, und fügen Sie ihr öffentliche Methoden hinzu. Clients können Methoden aufrufen, die als public definiert sind:
public class ChatHub : Hub
{
public Task SendMessage(string user, string message)
{
return Clients.All.SendAsync("ReceiveMessage", user, message);
}
}
Sie können wie in jeder C#-Methode einen Rückgabetyp und Parameter angeben, auch komplexe Typen und Arrays. SignalR behandelt die Serialisierung und Deserialisierung komplexer Objekte und Arrays in Ihren Parametern und Rückgabewerten.
Note
Hubs sind vorübergehende Objekte:
- Speichern Sie den Zustand nicht in einer Eigenschaft in der Hubklasse. Jeder Hubmethodenaufruf wird in einer neuen Hubinstanz ausgeführt.
- Instanziieren Sie einen Hub nicht direkt über Abhängigkeitsinjektion. Um Nachrichten von einer anderen Stelle in Ihrer Anwendung an einen Client zu senden, verwenden Sie
IHubContext. - Verwenden Sie
awaitbeim Aufrufen asynchroner Methoden, die davon abhängen, dass der Hub aktiv bleibt. Eine Methode wieClients.All.SendAsync(...)kann beispielsweise fehlschlagen, wenn sie ohneawaitaufgerufen wird und die Hubmethode abgeschlossen wird, bevorSendAsyncabgeschlossen ist.
Das Context-Objekt
Die Hub-Klasse verfügt über eine Context-Eigenschaft, die die folgenden Eigenschaften mit Informationen zur Verbindung enthält:
| Property | Description |
|---|---|
| ConnectionId | Ruft die eindeutige ID für die Verbindung ab, die von SignalR zugewiesen wird. Für jede Verbindung gibt es eine Verbindungs-ID. |
| UserIdentifier | Ruft den Benutzerbezeichner ab. SignalR verwendet standardmäßig den ClaimTypes.NameIdentifier von ClaimsPrincipal, der der Verbindung zugeordnet ist, als Benutzerbezeichner. |
| User | Ruft den ClaimsPrincipal ab, der dem aktuellen Benutzer zugeordnet ist. |
| Items | Ruft eine Schlüssel-Wert-Sammlung ab, die zum Freigeben von Daten innerhalb des Bereichs dieser Verbindung verwendet werden kann. Daten können in dieser Sammlung gespeichert werden und bleiben für die Verbindung über verschiedene Hubmethodenaufrufe hinweg bestehen. |
| Features | Ruft die Sammlung der Features ab, die für die Verbindung verfügbar sind. Derzeit ist diese Sammlung in den meisten Szenarien nicht erforderlich, daher wurde sie noch nicht ausführlich dokumentiert. |
| ConnectionAborted | Ruft ein CancellationToken ab, das eine Benachrichtigung sendet, wenn die Verbindung abgebrochen wird. |
Hub.Context enthält auch die folgenden Methoden:
| Method | Description |
|---|---|
| GetHttpContext | Gibt den HttpContext für die Verbindung zurück, oder null, wenn die Verbindung keiner HTTP-Anforderung zugeordnet ist. Für HTTP-Verbindungen können Sie diese Methode verwenden, um Informationen wie HTTP-Header und Abfragezeichenfolgen abzurufen. |
| Abort | Bricht die Verbindung ab. |
Das Clients-Objekt
Die Hub-Klasse verfügt über eine Clients-Eigenschaft, die die folgenden Eigenschaften für die Kommunikation zwischen Server und Client enthält:
| Property | Description |
|---|---|
| All | Ruft eine Methode auf allen verbundenen Clients auf. |
| Caller | Ruft eine Methode auf dem Client auf, die die Hubmethode aufgerufen hat |
| Others | Ruft eine Methode auf allen verbundenen Clients mit Ausnahme des Clients auf, der die Methode aufgerufen hat. |
Hub.Clients enthält auch die folgenden Methoden:
| Method | Description |
|---|---|
| AllExcept | Ruft eine Methode auf allen verbundenen Clients mit Ausnahme der angegebenen Verbindungen auf. |
| Client | Ruft eine Methode auf einem bestimmten verbundenen Client auf. |
| Clients | Ruft eine Methode bei bestimmten verbundenen Clients auf. |
| Group | Ruft eine Methode für alle Verbindungen in der angegebenen Gruppe auf. |
| GroupExcept | Ruft eine Methode für alle Verbindungen in der angegebenen Gruppe mit Ausnahme der angegebenen Verbindungen auf. |
| Groups | Ruft eine Methode für mehrere Gruppen von Verbindungen auf. |
| OthersInGroup | Ruft eine Methode für eine Gruppe von Verbindungen auf, wobei der Client, der die Hubmethode aufgerufen hat, ausgeschlossen wird. |
| User | Ruft eine Methode für alle Verbindungen auf, die einem bestimmten Benutzer zugeordnet sind. |
| Users | Ruft eine Methode für alle Verbindungen auf, die den angegebenen Benutzern zugeordnet sind. |
Jede Eigenschaft oder Methode in den vorherigen Tabellen gibt ein Objekt mit einer SendAsync-Methode zurück. Mit der SendAsync-Methode können Sie den Namen und die Parameter der Clientmethode angeben, die aufgerufen werden soll.
Senden von Nachrichten an Clients
Verwenden Sie die Eigenschaften des Clients-Objekts, um Aufrufe für bestimmte Clients auszuführen. Im folgenden Beispiel gibt es drei Hubmethoden:
-
SendMessagesendet mithilfe vonClients.Alleine Nachricht an alle verbundenen Clients . -
SendMessageToCallersendet mithilfe vonClients.Callereine Nachricht zurück an den Aufrufer. -
SendMessageToGroupsendet eine Nachricht an alle Clients in derSignalR Users-Gruppe.
public Task SendMessage(string user, string message)
{
return Clients.All.SendAsync("ReceiveMessage", user, message);
}
public Task SendMessageToCaller(string user, string message)
{
return Clients.Caller.SendAsync("ReceiveMessage", user, message);
}
public Task SendMessageToGroup(string user, string message)
{
return Clients.Group("SignalR Users").SendAsync("ReceiveMessage", user, message);
}
Stark typisierte Hubs
Ein Nachteil der Verwendung von SendAsync besteht darin, dass eine magische Zeichenfolge erforderlich ist, um die Clientmethode anzugeben, die aufgerufen werden soll. Dadurch kann es zu Laufzeitfehlern kommen, wenn der Methodenname falsch geschrieben ist oder im Client fehlt.
Eine Alternative zur Verwendung von SendAsync besteht darin, Hub stark zu typisieren mit Hub<T>. Im folgenden Beispiel wurden die ChatHub-Clientmethoden in eine Schnittstelle namens IChatClient extrahiert.
public interface IChatClient
{
Task ReceiveMessage(string user, string message);
}
Diese Schnittstelle kann verwendet werden, um das vorherige ChatHub-Beispiel umzugestalten:
public class StronglyTypedChatHub : Hub<IChatClient>
{
public async Task SendMessage(string user, string message)
{
await Clients.All.ReceiveMessage(user, message);
}
public Task SendMessageToCaller(string user, string message)
{
return Clients.Caller.ReceiveMessage(user, message);
}
}
Die Verwendung von Hub<IChatClient> ermöglicht die Überprüfung der Clientmethoden zur Kompilierzeit. Dadurch werden Probleme verhindert, die durch die Verwendung von magischen Zeichenfolgen verursacht werden, weil Hub<T> nur Zugriff auf die in der Schnittstelle definierten Methoden bereitstellen kann.
Die Verwendung eines stark typisierten Hub<T> deaktiviert die Möglichkeit, SendAsync zu verwenden. Alle Methoden, die für die Schnittstelle definiert sind, können weiterhin als asynchron definiert werden. Tatsächlich sollte jede dieser Methoden einen Task zurückgeben. Da es sich um eine Schnittstelle handelt, verwenden Sie nicht das async-Schlüsselwort. Beispiel:
public interface IClient
{
Task ClientMethod();
}
Note
Das Async-Suffix wird nicht aus dem Methodennamen entfernt. Wenn Ihre Client-Methode nicht mit .on('MyMethodAsync') definiert ist, sollten Sie nicht MyMethodAsync als Namen verwenden.
Ändern des Namens einer Hubmethode
Standardmäßig ist der Name einer Serverhubmethode der Name der .NET-Methode. Sie können jedoch das HubMethodName-Attribut verwenden, um diese Standardeinstellung zu ändern und manuell einen Namen für die Methode anzugeben. Der Client sollte diesen Namen anstelle des .NET-Methodennamens verwenden, wenn die Methode aufgerufen wird:
[HubMethodName("SendMessageToUser")]
public Task DirectMessage(string user, string message)
{
return Clients.User(user).SendAsync("ReceiveMessage", user, message);
}
Ereignisse für eine Verbindung verarbeiten
Die Hubs-API von SignalR stellt die virtuellen OnConnectedAsync- und OnDisconnectedAsync-Methoden zum Verwalten und Nachverfolgen von Verbindungen bereit. Überschreiben Sie die virtuelle OnConnectedAsync-Methode, um Aktionen auszuführen, wenn ein Client eine Verbindung mit dem Hub herstellt, ihn z. B. einer Gruppe hinzufügt:
public override async Task OnConnectedAsync()
{
await Groups.AddToGroupAsync(Context.ConnectionId, "SignalR Users");
await base.OnConnectedAsync();
}
Überschreiben Sie die virtuelle OnDisconnectedAsync-Methode, um Aktionen auszuführen, wenn ein Client die Verbindung trennt. Wenn der Client die Verbindung absichtlich trennt (z. B. durch Aufrufen von connection.stop()), lautet der exception-Parameter null. Wenn der Client jedoch aufgrund eines Fehlers getrennt wird (z. B. durch einen Netzwerkfehler), enthält der exception-Parameter eine Ausnahme, die den Fehler beschreibt:
public override async Task OnDisconnectedAsync(Exception exception)
{
await Clients.Group("SignalR Users").SendAsync("ReceiveMessage", "I", "disconnect");
await base.OnDisconnectedAsync(exception);
}
RemoveFromGroupAsync muss nicht in OnDisconnectedAsync aufgerufen werden, das Element wird automatisch für Sie verarbeitet.
Warning
Sicherheitswarnung: Die Offenlegung von ConnectionId kann zu einem böswilligen Identitätswechsel führen, wenn die Server- oder Clientversion von SignalR ASP.NET Core 2.2 oder früher ist.
Fehler behandeln
Ausnahmen, die in Ihren Hubmethoden ausgelöst werden, werden an den Client gesendet, der die Methode aufgerufen hat. Auf dem JavaScript-Client gibt die invoke-Methode eine JavaScript-Promise zurück. Wenn der Client einen Fehler mit einem an das Promise angefügten Handler unter Verwendung von catch empfängt, wird dieser aufgerufen und als JavaScript-Error-Objekt übergeben.
connection.invoke("SendMessage", user, message).catch(err => console.error(err));
Wenn Ihr Hub eine Ausnahme auslöst, werden Verbindungen nicht geschlossen. SignalR gibt standardmäßig eine generische Fehlermeldung an den Client zurück. Beispiel:
Microsoft.AspNetCore.SignalR.HubException: An unexpected error occurred invoking 'MethodName' on the server.
Unerwartete Ausnahmen enthalten häufig vertrauliche Informationen, z. B. den Namen eines Datenbankservers in einer Ausnahme, die ausgelöst wird, wenn die Datenbankverbindung fehlschlägt. SignalR stellt diese detaillierten Fehlermeldungen als Sicherheitsmaßnahme standardmäßig nicht zur Verfügung. Weitere Informationen dazu, warum Ausnahmedetails unterdrückt werden, finden Sie unter Sicherheitsüberlegungen in ASP.NET Core SignalR.
Wenn Sie eine außergewöhnliche Bedingung haben, die Sie an den Client weitergeben möchten, können Sie die HubException-Klasse verwenden. Wenn Sie eine HubException aus Ihrer Hubmethode auslösen, SignalR die gesamte Nachricht unverändert an den Client:
public Task ThrowException()
{
throw new HubException("This error will be sent to the client!");
}
Note
SignalR sendet nur die Message-Eigenschaft der Ausnahme an den Client. Die Stapelablaufverfolgung und andere Eigenschaften der Ausnahme stehen dem Client nicht zur Verfügung.