SignalRASP.NET Core .NET-Client

Mit ASP.NET Core SignalR .NET-Clientbibliothek können Sie über SignalR .NET-Apps mit Hubs kommunizieren.

Anzeigen oder Herunterladen von Beispielcode (Vorgehensweise zum Herunterladen)

Das Codebeispiel in diesem Artikel ist eine WPF-App, die den ASP.NET Core SignalR .NET-Client verwendet.

Installieren des SignalR .NET-Clientpakets

Microsoft.AspNetCore. SignalR Das Clientpaket ist erforderlich, damit .NET-Clients eine Verbindung mit SignalR Hubs herstellen können.

Um die Clientbibliothek zu installieren, führen Sie den folgenden Befehl im Fenster Paket-Manager-Konsole aus:

Install-Package Microsoft.AspNetCore.SignalR.Client

Verbinden zu einem Hub

Um eine Verbindung herzustellen, erstellen Sie einen , HubConnectionBuilder und rufen Sie Build auf. Die Hub-URL, das Protokoll, der Transporttyp, die Protokollebene, Header und andere Optionen können beim Erstellen einer Verbindung konfiguriert werden. Konfigurieren Sie alle erforderlichen Optionen, indem Sie eine der Methoden HubConnectionBuilder in Build einfügen. Starten Sie die Verbindung mit StartAsync .

using System;
using System.Threading.Tasks;
using System.Windows;
using Microsoft.AspNetCore.SignalR.Client;

namespace SignalRChatClient
{
    public partial class MainWindow : Window
    {
        HubConnection connection;
        public MainWindow()
        {
            InitializeComponent();

            connection = new HubConnectionBuilder()
                .WithUrl("http://localhost:53353/ChatHub")
                .Build();

            connection.Closed += async (error) =>
            {
                await Task.Delay(new Random().Next(0,5) * 1000);
                await connection.StartAsync();
            };
        }

        private async void connectButton_Click(object sender, RoutedEventArgs e)
        {
            connection.On<string, string>("ReceiveMessage", (user, message) =>
            {
                this.Dispatcher.Invoke(() =>
                {
                   var newMessage = $"{user}: {message}";
                   messagesList.Items.Add(newMessage);
                });
            });

            try
            {
                await connection.StartAsync();
                messagesList.Items.Add("Connection started");
                connectButton.IsEnabled = false;
                sendButton.IsEnabled = true;
            }
            catch (Exception ex)
            {
                messagesList.Items.Add(ex.Message);
            }
        }

        private async void sendButton_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                await connection.InvokeAsync("SendMessage", 
                    userTextBox.Text, messageTextBox.Text);
            }
            catch (Exception ex)
            {                
                messagesList.Items.Add(ex.Message);                
            }
        }
    }
}

Behandeln verloren gegangener Verbindungen

Automatisches Wiederherstellen der Verbindung

kann HubConnection so konfiguriert werden, dass die Verbindung mithilfe der -Methode WithAutomaticReconnect für automatisch wiederhergestellt HubConnectionBuilder wird. Standardmäßig wird die Verbindung nicht automatisch wiederhergestellt.

HubConnection connection= new HubConnectionBuilder()
    .WithUrl(new Uri("http://127.0.0.1:5000/chathub"))
    .WithAutomaticReconnect()
    .Build();

Ohne Parameter konfiguriert den Client so, dass WithAutomaticReconnect() er 0, 2, 10 bzw. 30 Sekunden wartet, bevor versucht wird, jeden Verbindungsversuch erneut herzustellen, und nach vier fehlgeschlagenen Versuchen beendet wird.

Bevor versucht wird, erneut eine Verbindung herzustellen, geht in den Zustand über HubConnection und gibt das Ereignis HubConnectionState.Reconnecting Reconnecting aus. Dies bietet die Möglichkeit, Benutzer zu warnen, dass die Verbindung verloren gegangen ist, und Benutzeroberflächenelemente zu deaktivieren. Nicht interaktive Apps können damit beginnen, Nachrichten in die Warteschlange zu warteschlangen oder zu löschen.

connection.Reconnecting += error =>
{
    Debug.Assert(connection.State == HubConnectionState.Reconnecting);

    // Notify users the connection was lost and the client is reconnecting.
    // Start queuing or dropping messages.

    return Task.CompletedTask;
};

Wenn der Client die Verbindung innerhalb der ersten vier Versuche erfolgreich wiederhergestellt hat, geht zurück in den Zustand und HubConnection Connected gibt das Ereignis Reconnected aus. Dies bietet die Möglichkeit, Benutzer darüber zu informieren, dass die Verbindung wiederhergestellt wurde, und alle Nachrichten in der Warteschlange aus der Warteschlange zu entfernen.

Da die Verbindung für den Server völlig neu aussieht, wird den Ereignishandlern eine ConnectionId Reconnected neue bereitgestellt.

Warnung

Der -Parameter des Ereignishandlers ist NULL, wenn zum Überspringen der Reconnected connectionId HubConnection Aushandlung konfiguriert wurde.

connection.Reconnected += connectionId =>
{
    Debug.Assert(connection.State == HubConnectionState.Connected);

    // Notify users the connection was reestablished.
    // Start dequeuing messages queued while reconnecting if any.

    return Task.CompletedTask;
};

WithAutomaticReconnect() konfiguriert nicht für wiederholungsversuche bei anfänglichen Startfehlern, sodass Startfehler HubConnection manuell behandelt werden müssen:

public static async Task<bool> ConnectWithRetryAsync(HubConnection connection, CancellationToken token)
{
    // Keep trying to until we can start or the token is canceled.
    while (true)
    {
        try
        {
            await connection.StartAsync(token);
            Debug.Assert(connection.State == HubConnectionState.Connected);
            return true;
        }
        catch when (token.IsCancellationRequested)
        {
            return false;
        }
        catch
        {
            // Failed to connect, trying again in 5000 ms.
            Debug.Assert(connection.State == HubConnectionState.Disconnected);
            await Task.Delay(5000);
        }
    }
}

Wenn der Client die Verbindung innerhalb der ersten vier Versuche nicht erfolgreich wiederhergestellt hat, geht in den Zustand über und HubConnection Disconnected gibt das Ereignis Closed aus. Dies bietet die Möglichkeit, zu versuchen, die Verbindung manuell neu zu starten oder Benutzer darüber zu informieren, dass die Verbindung dauerhaft verloren gegangen ist.

connection.Closed += error =>
{
    Debug.Assert(connection.State == HubConnectionState.Disconnected);

    // Notify users the connection has been closed or manually try to restart the connection.

    return Task.CompletedTask;
};

Um eine benutzerdefinierte Anzahl von Verbindungsversuchen vor dem Trennen oder Ändern der Zeitsteuerung für die wiederherzustellende Verbindung zu konfigurieren, akzeptiert ein Array von Zahlen, die die Verzögerung in Millisekunden darstellen, die gewartet werden soll, bevor jeder Verbindungsversuch gestartet WithAutomaticReconnect wird.

HubConnection connection= new HubConnectionBuilder()
    .WithUrl(new Uri("http://127.0.0.1:5000/chathub"))
    .WithAutomaticReconnect(new[] { TimeSpan.Zero, TimeSpan.Zero, TimeSpan.FromSeconds(10) })
    .Build();

    // .WithAutomaticReconnect(new[] { TimeSpan.Zero, TimeSpan.FromSeconds(2), TimeSpan.FromSeconds(10), TimeSpan.FromSeconds(30) }) yields the default behavior.

Im vorherigen Beispiel wird der so konfiguriert, dass sofort nach dem Verlust der Verbindung versucht wird, erneut HubConnection eine Verbindung herzustellen. Dies gilt auch für die Standardkonfiguration.

Wenn beim ersten Verbindungsversuch ein Fehler auftritt, wird der zweite Verbindungsversuch ebenfalls sofort gestartet, anstatt wie in der Standardkonfiguration zwei Sekunden zu warten.

Wenn der zweite Verbindungsversuch fehlschlägt, beginnt der dritte Verbindungsversuch in 10 Sekunden, was wiederum der Standardkonfiguration gleicht.

Das benutzerdefinierte Verhalten weicht dann erneut vom Standardverhalten ab, indem es nach dem dritten Fehler des Verbindungsversuchs beendet wird. In der Standardkonfiguration gibt es einen weiteren Verbindungsversuch in weiteren 30 Sekunden.

Wenn Sie noch mehr Kontrolle über die Zeitsteuerung und die Anzahl der automatischen Verbindungsversuche wünschen, akzeptiert ein Objekt, das die -Schnittstelle implementiert, die über eine einzelne Methode mit dem Namen WithAutomaticReconnect IRetryPolicy NextRetryDelay verfügt.

NextRetryDelay nimmt ein einzelnes Argument mit dem Typ RetryContext an. verfügt RetryContext über drei Eigenschaften: , und PreviousRetryCount , bei denen es sich um , a ElapsedTime RetryReason long TimeSpan Exception bzw. handelt. Vor dem ersten Verbindungsversuch ist sowohl als auch null, und ist die Ausnahme, durch die die PreviousRetryCount ElapsedTime Verbindung verloren gegangen RetryReason ist. Nach jedem fehlgeschlagenen Wiederholungsversuch wird um eins erhöht, wird aktualisiert, um die zeitzuverursachen, die bisher für die Wiederherstellung der Verbindung verwendet wurde, und ist die Ausnahme, die dazu führte, dass der letzte Verbindungsversuch fehlgeschlagen PreviousRetryCount ElapsedTime RetryReason ist.

NextRetryDelay muss entweder einen TimeSpan zurückgeben, der die Wartezeit vor dem nächsten Verbindungsversuch darstellt, oder , wenn die null verbindung nicht mehr hergestellt werden HubConnection soll.

public class RandomRetryPolicy : IRetryPolicy
{
    private readonly Random _random = new Random();

    public TimeSpan? NextRetryDelay(RetryContext retryContext)
    {
        // If we've been reconnecting for less than 60 seconds so far,
        // wait between 0 and 10 seconds before the next reconnect attempt.
        if (retryContext.ElapsedTime < TimeSpan.FromSeconds(60))
        {
            return TimeSpan.FromSeconds(_random.NextDouble() * 10);
        }
        else
        {
            // If we've been reconnecting for more than 60 seconds so far, stop reconnecting.
            return null;
        }
    }
}
HubConnection connection = new HubConnectionBuilder()
    .WithUrl(new Uri("http://127.0.0.1:5000/chathub"))
    .WithAutomaticReconnect(new RandomRetryPolicy())
    .Build();

Alternativ können Sie Code schreiben, mit dem der Client manuell wie unter Manuelles Wiederherstellen der Verbindung erneut verbunden wird.

Manuelles Wiederherstellen der Verbindung

Warnung

Vor 3.0 stellt der .NET-Client für die Verbindung SignalR nicht automatisch wieder her. Sie müssen Code schreiben, der den Client manuell erneut verbindet.

Verwenden Sie das Closed -Ereignis, um auf eine verlorene Verbindung zu reagieren. Beispielsweise können Sie die wiederhergestellte Verbindung automatisieren.

Das Closed -Ereignis erfordert einen Delegaten, der zurückgibt, wodurch Task asynchroner Code ohne Verwendung von ausgeführt werden async void kann. Um die Delegatsignatur in einem Synchron ausgeführten Ereignishandler zu Closed erfüllen, geben Sie Task.CompletedTask zurück:

connection.Closed += (error) => {
    // Do your close logic.
    return Task.CompletedTask;
};

Der Hauptgrund für die asynchrone Unterstützung ist, dass Sie die Verbindung neu starten können. Das Starten einer Verbindung ist eine asynchrone Aktion.

In einem Handler, der die Verbindung neu startet, sollten Sie auf eine zufällige Verzögerung warten, um eine Überlastung des Servers zu verhindern, wie Closed im folgenden Beispiel gezeigt:

connection.Closed += async (error) =>
{
    await Task.Delay(new Random().Next(0,5) * 1000);
    await connection.StartAsync();
};

Aufrufen von Hubmethoden vom Client

InvokeAsync ruft Methoden auf dem Hub auf. Übergeben Sie den Hub-Methodennamen und alle argumente, die in der Hubmethode definiert sind, an InvokeAsync . SignalR ist asynchron. Verwenden Sie daher async und , wenn Sie die await Aufrufe ausführen.

await connection.InvokeAsync("SendMessage", 
    userTextBox.Text, messageTextBox.Text);

Die InvokeAsync -Methode gibt eine Task zurück, die abgeschlossen wird, wenn die Servermethode zurückgegeben wird. Der Rückgabewert (sofern vorhanden) wird als Ergebnis von Task bereitgestellt. Alle Ausnahmen, die von der -Methode auf dem Server ausgelöst werden, erzeugen einen fehlerhaften Task . Verwenden await Sie syntax, um auf den Abschluss der Servermethode zu warten, und try...catch syntax zur Behandlung von Fehlern.

Die SendAsync -Methode gibt einen Task zurück, der abgeschlossen wird, wenn die Nachricht an den Server gesendet wurde. Es wird kein Rückgabewert bereitgestellt, da Task dies nicht wartet, bis die Servermethode abgeschlossen ist. Alle Ausnahmen, die beim Senden der Nachricht auf dem Client ausgelöst werden, erzeugen einen fehlerhaften Task . Verwenden Sie await die Syntax und , um try...catch Sendefehler zu behandeln.

Hinweis

Das Aufrufen von Hubmethoden von einem Client wird nur unterstützt, wenn der SignalR Azure-Dienst im Standardmodus verwendet wird. Weitere Informationen finden Sie unter Häufig gestellte Fragen (azure-signalr GitHub-Repository).

Aufrufen von Clientmethoden über den Hub

Definieren Sie Methoden, die der Hub nach dem Erstellen, aber vor connection.On dem Starten der Verbindung aufruft.

connection.On<string, string>("ReceiveMessage", (user, message) =>
{
    this.Dispatcher.Invoke(() =>
    {
       var newMessage = $"{user}: {message}";
       messagesList.Items.Add(newMessage);
    });
});

Der vorangehende Code in wird connection.On ausgeführt, wenn serverseitiger Code ihn mithilfe der -Methode SendAsync aufruft.

public async Task SendMessage(string user, string message)
{
    await Clients.All.SendAsync("ReceiveMessage", user,message);
}

Hinweis

Während die Hubseite der Verbindung stark typbasiertes Messaging unterstützt, muss sich der Client mithilfe der generischen Methode mit HubConnection.On dem Methodennamen registrieren. Ein Beispiel finden Sie unter Hosten ASP.NET Core SignalR in Hintergrunddiensten.

Fehlerbehandlung und Protokollierung

Behandeln Sie Fehler mit einer try-catch-Anweisung. Überprüfen Sie Exception das -Objekt, um die richtige Aktion zu bestimmen, die nach auftreten eines Fehlers erfolgen soll.

try
{
    await connection.InvokeAsync("SendMessage", 
        userTextBox.Text, messageTextBox.Text);
}
catch (Exception ex)
{                
    messagesList.Items.Add(ex.Message);                
}

Zusätzliche Ressourcen