SignalR-JavaScript-Client von ASP.NET Core
Von Rachel Appel
Mit der ASP.NET Core SignalR JavaScript-Clientbibliothek können Entwickler serverseitigen SignalR-Hubcode aufrufen.
Installieren des SignalR-Clientpakets
Die SignalR JavaScript-Clientbibliothek wird als npm-Paket geliefert. In den folgenden Abschnitten werden verschiedene Möglichkeiten zur Installation der Clientbibliothek beschrieben.
Installieren mit npm
Führen Sie die folgenden Befehle der Paket-Manager-Konsole aus:
npm init -y
npm install @microsoft/signalr
npm installiert die Paketinhalte in den Ordner node_modules\@microsoft\signalr\dist\browser. Erstellen Sie den Ordner wwwroot/lib/signalr. Kopieren Sie die Datei signalr.js
in den Ordner wwwroot/lib/signalr.
Verweisen Sie auf den SignalR JavaScript-Client im <script>
-Element. Beispiel:
<script src="~/lib/signalr/signalr.js"></script>
Verwenden eines Content Delivery Network (CDN)
Um die Clientbibliothek ohne die npm-Voraussetzung zu verwenden, verweisen Sie auf eine im CDN gehostete Kopie der Clientbibliothek. Beispiel:
<script src="https://cdnjs.cloudflare.com/ajax/libs/microsoft-signalr/6.0.1/signalr.js"></script>
Die Clientbibliothek ist in den folgenden CDNs verfügbar:
Installieren mit LibMan
LibMan kann verwendet werden, um bestimmte Dateien der Clientbibliothek aus der im CDN gehosteten Clientbibliothek zu installieren. Fügen Sie z. B. nur die minimierte JavaScript-Datei zum Projekt hinzu. Einzelheiten zu diesem Ansatz finden Sie unter Hinzufügen der SignalR-Clientbibliothek.
Verbinden mit einem Hub
Der folgende Code erstellt und startet eine Verbindung. Beim Namen des Hubs wird die Groß-/Kleinschreibung nicht beachtet:
const connection = new signalR.HubConnectionBuilder()
.withUrl("/chathub")
.configureLogging(signalR.LogLevel.Information)
.build();
async function start() {
try {
await connection.start();
console.log("SignalR Connected.");
} catch (err) {
console.log(err);
setTimeout(start, 5000);
}
};
connection.onclose(async () => {
await start();
});
// Start the connection.
start();
Ursprungsübergreifende Verbindungen (CORS)
Normalerweise laden Browser Verbindungen aus der gleichen Domäne wie die angeforderte Seite. Es gibt jedoch Fälle, in denen eine Verbindung zu einer anderen Domäne erforderlich ist.
Bei domänenübergreifenden Anforderungenmuss der Clientcode anstelle einer relativen URL eine absolute URL verwenden. Für domänenübergreifende Anforderungen ändern Sie .withUrl("/chathub")
in .withUrl("https://{App domain name}/chathub")
.
Um zu verhindern, dass eine böswillige Website vertrauliche Daten von einer anderen Website liest, sind ursprungsübergreifende Verbindungen standardmäßig deaktiviert. Um eine ursprungsübergreifende Anforderung zuzulassen, aktivieren Sie CORS:
using SignalRChat.Hubs;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddSignalR();
builder.Services.AddCors(options =>
{
options.AddDefaultPolicy(
builder =>
{
builder.WithOrigins("https://example.com")
.AllowAnyHeader()
.WithMethods("GET", "POST")
.AllowCredentials();
});
});
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
// UseCors must be called before MapHub.
app.UseCors();
app.MapRazorPages();
app.MapHub<ChatHub>("/chatHub");
app.Run();
UseCors muss vor dem Aufruf von MapHub aufgerufen werden.
Aufrufen von Hubmethoden über den Client
JavaScript-Clients rufen öffentliche Methoden auf Hubs über die invoke-Methode von HubConnection auf. Die invoke
-Methode akzeptiert Folgendes:
- Den Namen der Hubmethode.
- Alle in der Hubmethode definierten Argumente.
In dem folgenden hervorgehobenen Code lautet der Name der Methode auf dem Hub SendMessage
. Die an invoke
übergebenen zweiten und dritten Argumente entsprechen den Argumenten user
und message
der Hubmethode:
try {
await connection.invoke("SendMessage", user, message);
} catch (err) {
console.error(err);
}
Das Aufrufen von Hubmethoden durch einen Client wird nur bei Verwendung von Azure Service im Modus SignalRDefault unterstützt. Weitere Informationen finden Sie unter Häufig gestellte Fragen (GitHub-Repository azure-signalr).
Die invoke
-Methode gibt eine JavaScript-Promise
zurück. Die Promise
wird mit dem Rückgabewert (falls vorhanden) aufgelöst, wenn die Methode auf dem Server zurückkehrt. Wenn die Methode auf dem Server einen Fehler auslöst, wird die Promise
mit der Fehlermeldung zurückgewiesen. Verwenden Sie async
und await
oder die then
- und catch
-Methoden der Promise
, um diese Fälle zu behandeln.
JavaScript-Clients können über die send-Methode der HubConnection
auch öffentliche Methoden auf Hubs aufrufen. Anders als die Methode invoke
wartet die Methode send
nicht auf eine Antwort vom Server. Die send
-Methode gibt eine JavaScript-Promise
zurück. Die Promise
wird aufgelöst, wenn die Nachricht an den Server gesendet wurde. Wenn beim Senden der Nachricht ein Fehler auftritt, wird die Promise
mit der Fehlermeldung zurückgewiesen. Verwenden Sie async
und await
oder die then
- und catch
-Methoden der Promise
, um diese Fälle zu behandeln.
Bei der Verwendung von send
wird nicht gewartet, bis der Server die Nachricht empfangen hat. Folglich ist es nicht möglich, Daten oder Fehler vom Server zurückzugeben.
Aufrufen von Clientmethoden über den Hub
Um Nachrichten vom Hub zu empfangen, definieren Sie eine Methode mithilfe der on-Methode der HubConnection
.
- Der Name der JavaScript-Clientmethode.
- Argumente, die der Hub an die Methode übergibt.
Im folgenden Beispiel lautet der Name der Methode ReceiveMessage
. Die Namen der Argumente sind user
und message
:
connection.on("ReceiveMessage", (user, message) => {
const li = document.createElement("li");
li.textContent = `${user}: ${message}`;
document.getElementById("messageList").appendChild(li);
});
Der vorangehende Code in connection.on
wird ausgeführt, wenn der serverseitige Code ihn mithilfe der Methode SendAsync aufruft:
using Microsoft.AspNetCore.SignalR;
namespace SignalRChat.Hubs;
public class ChatHub : Hub
{
public async Task SendMessage(string user, string message)
{
await Clients.All.SendAsync("ReceiveMessage", user, message);
}
}
SignalR bestimmt, welche Clientmethode aufgerufen werden soll, indem der Name der Methode und die in SendAsync
und connection.on
definierten Argumente abgeglichen werden.
Eine bewährte Methode ist der Aufruf der start-Methode für die HubConnection
nach on
. Dadurch wird sichergestellt, dass die Handler registriert werden, bevor eine Nachricht empfangen wird.
Fehlerbehandlung und Protokollierung
Verwenden Sie console.error
, um Fehler in der Konsole des Browsers auszugeben, wenn der Client keine Verbindung herstellen oder keine Nachricht senden kann:
try {
await connection.invoke("SendMessage", user, message);
} catch (err) {
console.error(err);
}
Richten Sie die Ablaufverfolgung auf der Clientseite ein, indem Sie eine Protokollierung und den Typ des Ereignisses übergeben, der beim Herstellen der Verbindung protokolliert werden soll. Meldungen werden mit der angegebenen oder einer höheren Protokollstufe protokolliert. Folgende Protokollstufen sind verfügbar:
signalR.LogLevel.Error
: Fehlermeldungen. Protokolliert nurError
-Nachrichten.signalR.LogLevel.Warning
: Warnmeldungen über mögliche Fehler. ProtokolliertWarning
-, undError
-Nachrichten.signalR.LogLevel.Information
: Statusmeldungen ohne Fehler. ProtokolliertInformation
-,Warning
- undError
-Nachrichten.signalR.LogLevel.Trace
: Überwachungsnachrichten. Protokolliert alles, einschließlich der zwischen Hub und Client übertragenen Daten.
Verwenden Sie die configureLogging-Methode für HubConnectionBuilder, um die Protokollstufe zu konfigurieren. Die Nachrichten werden in der Browserkonsole protokolliert:
const connection = new signalR.HubConnectionBuilder()
.withUrl("/chathub")
.configureLogging(signalR.LogLevel.Information)
.build();
Wiederherstellen der Verbindung zwischen Clients
Automatisches Wiederherstellen der Verbindung
Der JavaScript-Client für SignalR kann so konfiguriert werden, dass er mithilfe der Methode WithAutomaticReconnect für HubConnectionBuilder automatisch die Verbindung wiederherstellt. Standardmäßig wird die Verbindung nicht automatisch wiederhergestellt.
const connection = new signalR.HubConnectionBuilder()
.withUrl("/chathub")
.withAutomaticReconnect()
.build();
Ohne Parameter konfiguriert WithAutomaticReconnect den Client so, dass er 0, 2, 10 bzw. 30 Sekunden wartet, bevor er jeweils versucht, die Verbindung wiederherzustellen. Nach vier Fehlversuchen wird die Verbindung nicht mehr wiederhergestellt.
Bevor Sie einen erneuten Verbindungsversuch starten, gilt Folgendes für die HubConnection
:
- Sie geht in den Zustand
HubConnectionState.Reconnecting
über und löst ihreonreconnecting
-Rückrufe aus. - Sie geht nicht in den Zustand
Disconnected
über und löst ihreonclose
-Rückrufe wie eineHubConnection
ohne konfiguriertes automatisches Wiederherstellen der Verbindung aus.
Der Ansatz zum Wiederherstellen der Verbindung bietet folgende Möglichkeiten:
- Warnen der Benutzer, dass die Verbindung unterbrochen wurde.
- Deaktivieren der Elemente der Benutzeroberfläche.
connection.onreconnecting(error => {
console.assert(connection.state === signalR.HubConnectionState.Reconnecting);
document.getElementById("messageInput").disabled = true;
const li = document.createElement("li");
li.textContent = `Connection lost due to error "${error}". Reconnecting.`;
document.getElementById("messageList").appendChild(li);
});
Wenn der Client die Verbindung innerhalb der ersten vier Versuche erfolgreich wiederherstellt, wechselt die HubConnection
zurück in den Zustand Connected
und löst ihre onreconnected
-Rückrufe aus. Dies bietet die Möglichkeit, den Benutzern mitzuteilen, dass die Verbindung wiederhergestellt wurde.
Da die Verbindung für den Server völlig neu aussieht, wird eine neue connectionId
für den onreconnected
-Rückruf bereitgestellt.
Der connectionId
-Parameter des onreconnected
-Rückrufs ist undefiniert, wenn die HubConnection
so konfiguriert ist, dass die Aushandlung übersprungen wird.
connection.onreconnected(connectionId => {
console.assert(connection.state === signalR.HubConnectionState.Connected);
document.getElementById("messageInput").disabled = false;
const li = document.createElement("li");
li.textContent = `Connection reestablished. Connected with connectionId "${connectionId}".`;
document.getElementById("messageList").appendChild(li);
});
withAutomaticReconnect
konfiguriert die HubConnection
nicht für die Wiederholung von anfänglichen Startfehlern, sodass Startfehler manuell behandelt werden müssen:
async function start() {
try {
await connection.start();
console.assert(connection.state === signalR.HubConnectionState.Connected);
console.log("SignalR Connected.");
} catch (err) {
console.assert(connection.state === signalR.HubConnectionState.Disconnected);
console.log(err);
setTimeout(() => start(), 5000);
}
};
Wenn der Client die Verbindung nicht innerhalb der ersten vier Versuche erfolgreich wiederherstellen kann, geht die HubConnection
in den Zustand Disconnected
über und löst ihre onclose-Rückrufe aus. Dies bietet die Möglichkeit, die Benutzer zu informieren:
- Die Verbindung wurde dauerhaft unterbrochen.
- Versuchen Sie, die Seite zu aktualisieren:
connection.onclose(error => {
console.assert(connection.state === signalR.HubConnectionState.Disconnected);
document.getElementById("messageInput").disabled = true;
const li = document.createElement("li");
li.textContent = `Connection closed due to error "${error}". Try refreshing this page to restart the connection.`;
document.getElementById("messageList").appendChild(li);
});
Um eine benutzerdefinierte Anzahl von Wiederverbindungsversuchen zu konfigurieren, bevor die Verbindung getrennt wird, oder um den Zeitpunkt der Verbindungswiederherstellung zu ändern, akzeptiert withAutomaticReconnect
ein Array von Zahlen, die die Verzögerung in Millisekunden angeben, die gewartet werden soll, ehe die einzelnen Wiederverbindungsversuche gestartet werden.
const connection = new signalR.HubConnectionBuilder()
.withUrl("/chathub")
.withAutomaticReconnect([0, 0, 10000])
.build();
// .withAutomaticReconnect([0, 2000, 10000, 30000]) yields the default behavior
Im vorhergehenden Beispiel wird HubConnection
so konfiguriert, dass sofort nach Unterbrechung der Verbindung ein neuer Verbindungsversuch unternommen wird. Die Standardkonfiguration wartet auch 0 Sekunden, bis versucht wird, die Verbindung wiederherzustellen.
Wenn der erste Wiederverbindungsversuch fehlschlägt, wird der zweite Wiederverbindungsversuch ebenfalls sofort gestartet, anstatt wie bei Verwendung der Standardkonfiguration zwei Sekunden zu warten.
Wenn der zweite Versuch zum Wiederherstellen der Verbindung fehlerhaft ist, wird der dritte Versuch zum Wiederherstellen der Verbindung nach 10 Sekunden gestartet, was wiederum der Standardkonfiguration entspricht.
Die konfigurierte Zeitsteuerung für die Wiederherstellung der Verbindung weicht vom Standardverhalten ab, indem nach dem dritten fehlerhaften Wiederherstellungsversuch abgebrochen wird, anstatt einen weiteren Wiederherstellungsversuch in weiteren 30 Sekunden zu unternehmen.
Um mehr Kontrolle über Zeitpunkt und Anzahl der Versuche zum automatischen Wiederherstellen der Verbindung zu erhalten, akzeptiert withAutomaticReconnect
ein Objekt, das die Schnittstelle IRetryPolicy
implementiert, die eine einzelne Methode namens nextRetryDelayInMilliseconds
aufweist.
nextRetryDelayInMilliseconds
übernimmt ein einzelnes Argument mit dem Typ RetryContext
. RetryContext
hat drei Eigenschaften: previousRetryCount
, elapsedMilliseconds
und retryReason
, die jeweils eine number
, eine number
und ein Error
sind. Vor dem ersten Wiederverbindungsversuch sind sowohl previousRetryCount
als auch elapsedMilliseconds
0, und retryReason
ist der Fehler, der den Verbindungsabbruch verursacht hat. Nach jedem fehlgeschlagenen Versuch zum Wiederherstellen der Verbindung wird previousRetryCount
um 1 erhöht, elapsedMilliseconds
wird aktualisiert, um die bisher für den Versuch zum Wiederherstellen der Verbindung aufgewendete Zeit in Millisekunden wiederzugeben, und retryReason
ist der Fehler, der den letzten Versuch zum Wiederherstellen der Verbindung fehlschlagen ließ.
nextRetryDelayInMilliseconds
muss entweder eine Zahl zurückgeben, die die Anzahl der Millisekunden angibt, die vor dem nächsten Versuch zum Wiederherstellen der Verbindung gewartet werden soll, oder null
, wenn die HubConnection
den Versuch zum Wiederherstellen der Verbindung beenden soll.
const connection = new signalR.HubConnectionBuilder()
.withUrl("/chathub")
.withAutomaticReconnect({
nextRetryDelayInMilliseconds: retryContext => {
if (retryContext.elapsedMilliseconds < 60000) {
// If we've been reconnecting for less than 60 seconds so far,
// wait between 0 and 10 seconds before the next reconnect attempt.
return Math.random() * 10000;
} else {
// If we've been reconnecting for more than 60 seconds so far, stop reconnecting.
return null;
}
}
})
.build();
Alternativ kann ein Code geschrieben werden, der die Verbindung zum Client manuell wiederherstellt, wie im folgenden Abschnitt gezeigt wird.
Manuelles Wiederherstellen der Verbindung
Der folgende Code veranschaulicht einen typischen Versuch zum manuellen Wiederherstellen der Verbindung:
- Es wird eine Funktion (in diesem Fall die Funktion
start
) erstellt, um die Verbindung zu starten. - Rufen Sie die Funktion
start
im Ereignishandleronclose
der Verbindung auf.
async function start() {
try {
await connection.start();
console.log("SignalR Connected.");
} catch (err) {
console.log(err);
setTimeout(start, 5000);
}
};
connection.onclose(async () => {
await start();
});
Produktionsimplementierungen verwenden in der Regel ein exponentielles Backoff oder versuchen es eine bestimmte Anzahl von Malen erneut.
Browser: Registerkarte im Ruhezustand
Einige Browser verfügen über ein Feature zum Einfrieren von Registerkarten oder zum Versetzen dieser Registerkarten in den Ruhezustand, um die Nutzung von Computerressourcen für inaktive Registerkarten zu reduzieren. Dies kann dazu führen, dass SignalR-Verbindungen geschlossen werden, was zu einer unerwünschten Benutzererfahrung führen kann. Browser verwenden Heuristiken, um herauszufinden, ob eine Registerkarte in den Ruhezustand versetzt werden sollte. Beispiel:
- Audiowiedergabe
- Festlegen einer Websperre
- Festlegen einer
IndexedDB
-Sperre - Bestehende Verbindung mit einem USB-Gerät
- Video- oder Audioaufzeichnung
- Erstellen einer Spiegelung
- Erfassen eines Fensters oder einer Anzeige
Die Browserheuristik kann sich im Laufe der Zeit ändern und von Browser zu Browser unterschiedlich sein. Überprüfen Sie die Supportmatrix und ermitteln Sie, welche Methode für Ihre Szenarien am besten geeignet ist.
Um zu vermeiden, dass eine App in den Ruhezustand versetzt wird, sollte die App eine der Heuristiken auslösen, die der Browser verwendet.
Das folgende Codebeispiel zeigt, wie Sie eine Websperre verwenden, damit eine Registerkarte aktiv bleibt und ein unerwartetes Schließen der Verbindung vermieden wird.
var lockResolver;
if (navigator && navigator.locks && navigator.locks.request) {
const promise = new Promise((res) => {
lockResolver = res;
});
navigator.locks.request('unique_lock_name', { mode: "shared" }, () => {
return promise;
});
}
Für das vorangehende Codebeispiel:
- Websperren sind experimentell. Die bedingte Überprüfung bestätigt, dass der Browser Websperren unterstützt.
- Die Zusageauflösung
lockResolver
wird gespeichert, sodass die Sperre freigegeben werden kann, wenn die Registerkarte in den Ruhezustand wechseln darf. - Wenn Sie die Verbindung schließen, wird die Sperre durch den Aufruf von
lockResolver()
freigegeben. Wenn die Sperre freigegeben wird, kann die Registerkarte in den Ruhezustand versetzt werden.
Zusätzliche Ressourcen
- Anzeigen oder Herunterladen von Beispielcode (Vorgehensweise zum Herunterladen)
- JavaScript-API-Referenz
- Tutorial zu JavaScript
- Tutorial zu WebPack und TypeScript
- Hubs
- .NET-Client
- Veröffentlichen in Azure
- Ursprungsübergreifende Anforderungen (CORS)
- Dokumentation zu serverlosem Azure SignalR Service
- Beheben von Verbindungsproblemen
Von Rachel Appel
Die ASP.NET Core SignalR-Clientbibliothek für JavaScript ermöglicht es Entwicklern, serverseitigen Hubcode aufzurufen.
Anzeigen oder Herunterladen von Beispielcode (Vorgehensweise zum Herunterladen)
Installieren des SignalR-Clientpakets
Die SignalR JavaScript-Clientbibliothek wird als npm-Paket geliefert. In den folgenden Abschnitten werden verschiedene Möglichkeiten zur Installation der Clientbibliothek beschrieben.
Installieren mit npm
Für Visual Studio führen Sie die folgenden Befehle der Paket-Manager-Konsole aus, während Sie sich im Stammordner befinden. Für Visual Studio Code führen Sie die folgenden Befehle über das integrierte Terminal aus.
npm init -y
npm install @microsoft/signalr
npm installiert die Paketinhalte in den Ordner node_modules\@microsoft\signalr\dist\browser. Erstellen Sie einen neuen Ordner namens signalr unter dem Ordner wwwroot\lib. Kopieren Sie die Datei signalr.js
in den Ordner wwwroot\lib\signalr.
Verweisen Sie auf den SignalR JavaScript-Client im <script>
-Element. Beispiel:
<script src="~/lib/signalr/signalr.js"></script>
Verwenden eines Content Delivery Network (CDN)
Um die Clientbibliothek ohne die npm-Voraussetzung zu verwenden, verweisen Sie auf eine im CDN gehostete Kopie der Clientbibliothek. Beispiel:
<script src="https://cdnjs.cloudflare.com/ajax/libs/microsoft-signalr/3.1.7/signalr.js"></script>
Die Clientbibliothek ist in den folgenden CDNs verfügbar:
Installieren mit LibMan
LibMan kann verwendet werden, um bestimmte Dateien der Clientbibliothek aus der im CDN gehosteten Clientbibliothek zu installieren. Fügen Sie z. B. nur die minimierte JavaScript-Datei zum Projekt hinzu. Einzelheiten zu diesem Ansatz finden Sie unter Hinzufügen der SignalR-Clientbibliothek.
Verbinden mit einem Hub
Der folgende Code erstellt und startet eine Verbindung. Beim Namen des Hubs wird die Groß-/Kleinschreibung nicht beachtet:
const connection = new signalR.HubConnectionBuilder()
.withUrl("/chathub")
.configureLogging(signalR.LogLevel.Information)
.build();
async function start() {
try {
await connection.start();
console.log("SignalR Connected.");
} catch (err) {
console.log(err);
setTimeout(start, 5000);
}
};
connection.onclose(async () => {
await start();
});
// Start the connection.
start();
Ursprungsübergreifende Verbindungen
Normalerweise laden Browser Verbindungen aus der gleichen Domäne wie die angeforderte Seite. Es gibt jedoch Fälle, in denen eine Verbindung zu einer anderen Domäne erforderlich ist.
Wichtig
Der Clientcode muss eine absolute URL anstelle einer relativen URL verwenden. Wechseln von .withUrl("/chathub")
zu .withUrl("https://myappurl/chathub")
.
Um zu verhindern, dass eine böswillige Website vertrauliche Daten von einer anderen Website liest, sind ursprungsübergreifende Verbindungen standardmäßig deaktiviert. Um eine ursprungsübergreifende Anforderung zuzulassen, aktivieren Sie sie in der Klasse Startup
:
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using SignalRChat.Hubs;
namespace SignalRChat
{
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddRazorPages();
services.AddSignalR();
services.AddCors(options =>
{
options.AddDefaultPolicy(builder =>
{
builder.WithOrigins("https://example.com")
.AllowCredentials();
});
});
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
}
app.UseStaticFiles();
app.UseRouting();
app.UseCors();
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
endpoints.MapHub<ChatHub>("/chathub");
});
}
}
}
Aufrufen von Hubmethoden über den Client
JavaScript-Clients rufen öffentliche Methoden auf Hubs über die invoke-Methode von HubConnection auf. Die invoke
-Methode akzeptiert Folgendes:
- Den Namen der Hubmethode.
- Alle in der Hubmethode definierten Argumente.
Im folgenden Beispiel lautet der Name der Methode für den Hub SendMessage
. Die an invoke
übergebenen zweiten und dritten Argumente entsprechen den Argumenten user
und message
der Hubmethode:
try {
await connection.invoke("SendMessage", user, message);
} catch (err) {
console.error(err);
}
Hinweis
Das Aufrufen von Hubmethoden durch einen Client wird nur bei Verwendung von Azure SignalR Service im Modus Default unterstützt. Weitere Informationen finden Sie unter Häufig gestellte Fragen (GitHub-Repository azure-signalr).
Die invoke
-Methode gibt eine JavaScript-Promise
zurück. Die Promise
wird mit dem Rückgabewert (falls vorhanden) aufgelöst, wenn die Methode auf dem Server zurückkehrt. Wenn die Methode auf dem Server einen Fehler auslöst, wird die Promise
mit der Fehlermeldung zurückgewiesen. Verwenden Sie async
und await
oder die then
- und catch
-Methoden der Promise
, um diese Fälle zu behandeln.
JavaScript-Clients können über die send-Methode der HubConnection
auch öffentliche Methoden auf Hubs aufrufen. Anders als die Methode invoke
wartet die Methode send
nicht auf eine Antwort vom Server. Die send
-Methode gibt eine JavaScript-Promise
zurück. Die Promise
wird aufgelöst, wenn die Nachricht an den Server gesendet wurde. Wenn beim Senden der Nachricht ein Fehler auftritt, wird die Promise
mit der Fehlermeldung zurückgewiesen. Verwenden Sie async
und await
oder die then
- und catch
-Methoden der Promise
, um diese Fälle zu behandeln.
Hinweis
Bei der Verwendung von send
wird nicht gewartet, bis der Server die Nachricht empfangen hat. Folglich ist es nicht möglich, Daten oder Fehler vom Server zurückzugeben.
Aufrufen von Clientmethoden über den Hub
Um Nachrichten vom Hub zu empfangen, definieren Sie eine Methode mithilfe der on-Methode der HubConnection
.
- Der Name der JavaScript-Clientmethode.
- Argumente, die der Hub an die Methode übergibt.
Im folgenden Beispiel lautet der Name der Methode ReceiveMessage
. Die Namen der Argumente sind user
und message
:
connection.on("ReceiveMessage", (user, message) => {
const li = document.createElement("li");
li.textContent = `${user}: ${message}`;
document.getElementById("messageList").appendChild(li);
});
Der vorangehende Code in connection.on
wird ausgeführt, wenn der serverseitige Code ihn mithilfe der Methode SendAsync aufruft:
public async Task SendMessage(string user, string message)
{
await Clients.All.SendAsync("ReceiveMessage", user, message);
}
SignalR bestimmt, welche Clientmethode aufgerufen werden soll, indem der Name der Methode und die in SendAsync
und connection.on
definierten Argumente abgeglichen werden.
Hinweis
Als bewährte Methode rufen Sie die start-Methode auf dem HubConnection
nach on
auf. So stellen Sie sicher, dass Ihre Handler registriert werden, bevor eine Nachricht empfangen wird.
Fehlerbehandlung und Protokollierung
Verwenden Sie try
und catch
mit async
und await
oder der Methode catch
der Promise
, um clientseitige Fehler zu behandeln. Verwenden Sie console.error
, um Fehler in der Konsole des Browsers auszugeben:
try {
await connection.invoke("SendMessage", user, message);
} catch (err) {
console.error(err);
}
Richten Sie die Ablaufverfolgung auf der Clientseite ein, indem Sie eine Protokollierung und den Typ des Ereignisses übergeben, der beim Herstellen der Verbindung protokolliert werden soll. Meldungen werden mit der angegebenen oder einer höheren Protokollstufe protokolliert. Folgende Protokollstufen sind verfügbar:
signalR.LogLevel.Error
: Fehlermeldungen. Protokolliert nurError
-Nachrichten.signalR.LogLevel.Warning
: Warnmeldungen über mögliche Fehler. ProtokolliertWarning
-, undError
-Nachrichten.signalR.LogLevel.Information
: Statusmeldungen ohne Fehler. ProtokolliertInformation
-,Warning
- undError
-Nachrichten.signalR.LogLevel.Trace
: Überwachungsnachrichten. Protokolliert alles, einschließlich der zwischen Hub und Client übertragenen Daten.
Verwenden Sie die configureLogging-Methode für HubConnectionBuilder, um die Protokollstufe zu konfigurieren. Die Nachrichten werden in der Browserkonsole protokolliert:
const connection = new signalR.HubConnectionBuilder()
.withUrl("/chathub")
.configureLogging(signalR.LogLevel.Information)
.build();
Wiederherstellen der Verbindung zwischen Clients
Automatisches Wiederherstellen der Verbindung
Der JavaScript-Client für SignalR kann so konfiguriert werden, dass er mithilfe der Methode withAutomaticReconnect
für HubConnectionBuilder automatisch die Verbindung wiederherstellt. Standardmäßig wird die Verbindung nicht automatisch wiederhergestellt.
const connection = new signalR.HubConnectionBuilder()
.withUrl("/chathub")
.withAutomaticReconnect()
.build();
Ohne Parameter wird der Client durch withAutomaticReconnect()
so konfiguriert, dass er 0, 2, 10 bzw. 30 Sekunden wartet, ehe er einen erneuten Verbindungsversuch unternimmt, und nach vier fehlgeschlagenen Versuchen beendet wird.
Vor dem Starten der Versuche zum Wiederherstellen der Verbindung geht die HubConnection
in den Zustand HubConnectionState.Reconnecting
über und löst ihre onreconnecting
-Rückrufe aus, anstatt in den Zustand Disconnected
überzugehen und ihre onclose
-Rückrufe auszulösen wie eine HubConnection
ohne konfiguriertes automatisches Wiederherstellen der Verbindung. Dies bietet die Möglichkeit, Benutzer zu warnen, dass die Verbindung unterbrochen wurde, und Benutzeroberflächenelemente zu deaktivieren.
connection.onreconnecting(error => {
console.assert(connection.state === signalR.HubConnectionState.Reconnecting);
document.getElementById("messageInput").disabled = true;
const li = document.createElement("li");
li.textContent = `Connection lost due to error "${error}". Reconnecting.`;
document.getElementById("messageList").appendChild(li);
});
Wenn der Client die Verbindung innerhalb der ersten vier Versuche erfolgreich wiederherstellt, wechselt die HubConnection
wieder in den Zustand Connected
und löst ihre onreconnected
-Rückrufe aus. Dies bietet die Möglichkeit, den Benutzern mitzuteilen, dass die Verbindung wiederhergestellt wurde.
Da die Verbindung für den Server völlig neu aussieht, wird eine neue connectionId
für den onreconnected
-Rückruf bereitgestellt.
Warnung
Der connectionId
-Parameter des onreconnected
-Rückrufs ist undefiniert, wenn der HubConnection
-Rückruf so konfiguriert wurde, dass die Aushandlung übersprungen wird.
connection.onreconnected(connectionId => {
console.assert(connection.state === signalR.HubConnectionState.Connected);
document.getElementById("messageInput").disabled = false;
const li = document.createElement("li");
li.textContent = `Connection reestablished. Connected with connectionId "${connectionId}".`;
document.getElementById("messageList").appendChild(li);
});
withAutomaticReconnect()
konfiguriert die HubConnection
nicht für die Wiederholung von anfänglichen Startfehlern, sodass Startfehler manuell behandelt werden müssen:
async function start() {
try {
await connection.start();
console.assert(connection.state === signalR.HubConnectionState.Connected);
console.log("SignalR Connected.");
} catch (err) {
console.assert(connection.state === signalR.HubConnectionState.Disconnected);
console.log(err);
setTimeout(() => start(), 5000);
}
};
Wenn der Client die Verbindung nicht innerhalb der ersten vier Versuche erfolgreich wiederherstellen kann, geht die HubConnection
in den Zustand Disconnected
über und löst ihre onclose-Rückrufe aus. Dies bietet die Möglichkeit, den Benutzer darüber zu informieren, dass die Verbindung dauerhaft unterbrochen wurde, und ihm zu empfehlen, die Seite zu aktualisieren:
connection.onclose(error => {
console.assert(connection.state === signalR.HubConnectionState.Disconnected);
document.getElementById("messageInput").disabled = true;
const li = document.createElement("li");
li.textContent = `Connection closed due to error "${error}". Try refreshing this page to restart the connection.`;
document.getElementById("messageList").appendChild(li);
});
Um eine benutzerdefinierte Anzahl von Wiederverbindungsversuchen zu konfigurieren, bevor die Verbindung getrennt wird, oder um den Zeitpunkt der Verbindungswiederherstellung zu ändern, akzeptiert withAutomaticReconnect
ein Array von Zahlen, die die Verzögerung in Millisekunden angeben, die gewartet werden soll, ehe die einzelnen Wiederverbindungsversuche gestartet werden.
const connection = new signalR.HubConnectionBuilder()
.withUrl("/chathub")
.withAutomaticReconnect([0, 0, 10000])
.build();
// .withAutomaticReconnect([0, 2000, 10000, 30000]) yields the default behavior
Im vorhergehenden Beispiel wird HubConnection
so konfiguriert, dass sofort nach Unterbrechung der Verbindung ein neuer Verbindungsversuch unternommen wird. Dies gilt auch für die Standardkonfiguration.
Wenn der erste Wiederverbindungsversuch fehlschlägt, wird der zweite Wiederverbindungsversuch ebenfalls sofort gestartet, anstatt wie in der Standardkonfiguration zwei Sekunden zu warten.
Wenn der zweite Versuch zum Wiederherstellen der Verbindung fehlschlägt, wird der dritte Versuch zum Wiederherstellen der Verbindung nach 10 Sekunden gestartet, was wiederum der Standardkonfiguration entspricht.
Das benutzerdefinierte Verhalten weicht dann wieder vom Standardverhalten ab, indem es nach dem dritten fehlerhaften Versuch zum Wiederherstellen der Verbindung stoppt, anstatt wie in der Standardkonfiguration einen weiteren Versuch zum Wiederherstellen der Verbindung in weiteren 30 Sekunden zu unternehmen.
Wenn Sie noch mehr Kontrolle über Zeitpunkt und Anzahl der automatischen Versuche zum Wiederherstellen der Verbindung wünschen, akzeptiert withAutomaticReconnect
ein Objekt, das die IRetryPolicy
-Schnittstelle implementiert, die eine einzelne Methode namens nextRetryDelayInMilliseconds
aufweist.
nextRetryDelayInMilliseconds
übernimmt ein einzelnes Argument mit dem Typ RetryContext
. RetryContext
hat drei Eigenschaften: previousRetryCount
, elapsedMilliseconds
und retryReason
, die jeweils eine number
, eine number
und ein Error
sind. Vor dem ersten Wiederverbindungsversuch sind sowohl previousRetryCount
als auch elapsedMilliseconds
0, und retryReason
ist der Fehler, der den Verbindungsabbruch verursacht hat. Nach jedem fehlgeschlagenen Versuch zum Wiederherstellen der Verbindung wird previousRetryCount
um 1 erhöht, elapsedMilliseconds
wird aktualisiert, um die bisher für den Versuch zum Wiederherstellen der Verbindung aufgewendete Zeit in Millisekunden wiederzugeben, und retryReason
ist der Fehler, der den letzten Versuch zum Wiederherstellen der Verbindung fehlschlagen ließ.
nextRetryDelayInMilliseconds
muss entweder eine Zahl zurückgeben, die die Anzahl der Millisekunden angibt, die vor dem nächsten Versuch zum Wiederherstellen der Verbindung gewartet werden soll, oder null
, wenn die HubConnection
den Versuch zum Wiederherstellen der Verbindung beenden soll.
const connection = new signalR.HubConnectionBuilder()
.withUrl("/chathub")
.withAutomaticReconnect({
nextRetryDelayInMilliseconds: retryContext => {
if (retryContext.elapsedMilliseconds < 60000) {
// If we've been reconnecting for less than 60 seconds so far,
// wait between 0 and 10 seconds before the next reconnect attempt.
return Math.random() * 10000;
} else {
// If we've been reconnecting for more than 60 seconds so far, stop reconnecting.
return null;
}
}
})
.build();
Alternativ können Sie Code schreiben, der die Verbindung zu Ihrem Client manuell wiederherstellt, wie unter Manuelles Wiederherstellen der Verbindung gezeigt.
Manuelles Wiederherstellen der Verbindung
Der folgende Code veranschaulicht einen typischen Versuch zum manuellen Wiederherstellen der Verbindung:
- Es wird eine Funktion (in diesem Fall die Funktion
start
) erstellt, um die Verbindung zu starten. - Rufen Sie die Funktion
start
im Ereignishandleronclose
der Verbindung auf.
async function start() {
try {
await connection.start();
console.log("SignalR Connected.");
} catch (err) {
console.log(err);
setTimeout(start, 5000);
}
};
connection.onclose(async () => {
await start();
});
Produktionsimplementierungen verwenden in der Regel ein exponentielles Backoff oder versuchen es eine bestimmte Anzahl von Malen erneut.
Browser: Registerkarte im Ruhezustand
Einige Browser verfügen über ein Feature zum Einfrieren von Registerkarten oder zum Versetzen dieser Registerkarten in den Ruhezustand, um die Nutzung von Computerressourcen für inaktive Registerkarten zu reduzieren. Dies kann dazu führen, dass SignalR-Verbindungen geschlossen werden, was zu einer unerwünschten Benutzererfahrung führen kann. Browser verwenden Heuristiken, um herauszufinden, ob eine Registerkarte in den Ruhezustand versetzt werden sollte. Beispiel:
- Audiowiedergabe
- Festlegen einer Websperre
- Festlegen einer
IndexedDB
-Sperre - Bestehende Verbindung mit einem USB-Gerät
- Video- oder Audioaufzeichnung
- Erstellen einer Spiegelung
- Erfassen eines Fensters oder einer Anzeige
Hinweis
Diese Heuristiken können sich im Laufe der Zeit ändern oder von Browser zu Browser unterschiedlich sein. Überprüfen Sie Ihre Supportmatrix und ermitteln Sie, welche Methode für Ihre Szenarien am besten geeignet ist.
Um zu vermeiden, dass eine App in den Ruhezustand versetzt wird, sollte die App eine der Heuristiken auslösen, die der Browser verwendet.
Das folgende Codebeispiel zeigt, wie Sie eine Websperre verwenden, damit eine Registerkarte aktiv bleibt und ein unerwartetes Schließen der Verbindung vermieden wird.
var lockResolver;
if (navigator && navigator.locks && navigator.locks.request) {
const promise = new Promise((res) => {
lockResolver = res;
});
navigator.locks.request('unique_lock_name', { mode: "shared" }, () => {
return promise;
});
}
Für das vorangehende Codebeispiel:
- Websperren sind experimentell. Die bedingte Überprüfung bestätigt, dass der Browser Websperren unterstützt.
- Die Zusageauflösung (
lockResolver
) wird gespeichert, sodass die Sperre freigegeben werden kann, wenn die Registerkarte in den Ruhezustand wechseln darf. - Wenn Sie die Verbindung schließen, wird die Sperre durch den Aufruf von
lockResolver()
freigegeben. Wenn die Sperre freigegeben wird, kann die Registerkarte in den Ruhezustand versetzt werden.
Zusätzliche Ressourcen
ASP.NET Core