Klient platformy .NET platformy ASP.NET Core SignalR

Biblioteka klienta platformy .NET platformy ASP.NET Core SignalR umożliwia komunikację z koncentratorami SignalR z aplikacji platformy .NET.

Wyświetl lub pobierz przykładowy kod (jak pobrać)

Przykładowy kod w tym artykule to aplikacja WPF korzystająca z klienta platformy .NET platformy .NET platformy ASP.NET Core SignalR .

Instalowanie pakietu klienta platformy SignalR .NET

Microsoft.AspNetCore .SignalR. Pakiet klienta jest wymagany dla klientów platformy .NET w celu nawiązania połączenia z SignalR koncentratorami.

Aby zainstalować bibliotekę klienta, uruchom następujące polecenie w oknie konsoli Menedżer pakietów:

Install-Package Microsoft.AspNetCore.SignalR.Client

Połączenie do koncentratora

Aby nawiązać połączenie, utwórz element i wywołaj metodę HubConnectionBuilderBuild. Adres URL centrum, protokół, typ transportu, poziom dziennika, nagłówki i inne opcje można skonfigurować podczas tworzenia połączenia. Skonfiguruj wszystkie wymagane opcje, wstawiając dowolną metodę HubConnectionBuilder do Buildmetody . Uruchom połączenie za pomocą polecenia 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);                
            }
        }
    }
}

Obsługa utraconego połączenia

Automatyczne ponowne nawiązywanie połączenia

Można HubConnection go skonfigurować tak, aby automatycznie ponownie nawiązać połączenie przy użyciu WithAutomaticReconnect metody w pliku HubConnectionBuilder. Domyślnie nie zostanie automatycznie ponownie nawiązane połączenie.

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

Bez żadnych parametrów WithAutomaticReconnect() klient konfiguruje odpowiednio odczekanie 0, 2, 10 i 30 sekund przed próbą ponownego nawiązania połączenia, zatrzymanie po czterech nieudanych próbach.

Przed rozpoczęciem wszelkich ponownych HubConnection prób nawiązania połączenia program przejdzie do HubConnectionState.Reconnecting stanu i uruchomi Reconnecting zdarzenie. Zapewnia to możliwość ostrzeżenia użytkowników o utracie połączenia i wyłączeniu elementów interfejsu użytkownika. Aplikacje nieinterakcyjne mogą rozpoczynać kolejkowanie lub upuszczać komunikaty.

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;
};

Jeśli klient pomyślnie połączy się ponownie w ramach pierwszych czterech prób, HubConnection nastąpi powrót do Connected stanu i wyzwolenie Reconnected zdarzenia. Zapewnia to możliwość poinformowania użytkowników o ponownym opublikowaniu połączenia i usunięciu z kolejki wszystkich komunikatów w kolejce.

Ponieważ połączenie wygląda zupełnie nowe na serwerze, ConnectionId nowe zostaną udostępnione programom obsługi zdarzeń Reconnected .

Ostrzeżenie

Reconnected Parametr programu obsługi connectionId zdarzeń będzie miał wartość null, jeśli HubConnection parametr został skonfigurowany do pomijania negocjacji.

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() Program nie skonfiguruje elementu , aby ponowić HubConnection próbę początkowych niepowodzeń uruchamiania, dlatego błędy uruchamiania muszą być obsługiwane ręcznie:

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);
        }
    }
}

Jeśli klient nie połączy się ponownie w ramach pierwszych czterech prób, HubConnection nastąpi przejście do Disconnected stanu i wyzwolenie Closed zdarzenia. Dzięki temu można spróbować ponownie uruchomić połączenie ręcznie lub poinformować użytkowników, że połączenie zostało trwale utracone.

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;
};

Aby skonfigurować niestandardową liczbę ponownych prób ponownego połączenia przed rozłączeniem lub zmianą czasu ponownego połączenia, WithAutomaticReconnect akceptuje tablicę liczb reprezentujących opóźnienie w milisekundach oczekiwania przed rozpoczęciem każdej próby ponownego nawiązania połączenia.

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.

W poprzednim przykładzie skonfigurowana jest wartość HubConnection , aby rozpocząć ponowne nawiązywanie połączeń natychmiast po utracie połączenia. Dotyczy to również konfiguracji domyślnej.

Jeśli pierwsza próba ponownego nawiązania połączenia zakończy się niepowodzeniem, druga próba ponownego połączenia zostanie również uruchomiona natychmiast zamiast czekać 2 sekundy, tak jak w konfiguracji domyślnej.

Jeśli druga próba ponownego nawiązania połączenia zakończy się niepowodzeniem, trzecia próba ponownego nawiązania połączenia rozpocznie się w ciągu 10 sekund, co jest ponownie podobne do konfiguracji domyślnej.

Zachowanie niestandardowe ponownie odbiega od domyślnego zachowania, zatrzymując się po trzecim niepowodzeniu ponownego nawiązania połączenia. W konfiguracji domyślnej będzie jeszcze jedna próba ponownego nawiązania połączenia w ciągu kolejnych 30 sekund.

Jeśli chcesz mieć jeszcze większą kontrolę nad chronometrażem i liczbą automatycznych ponownych prób ponownego łączenia, WithAutomaticReconnect akceptuje obiekt implementjący IRetryPolicy interfejs, który ma jedną metodę o nazwie NextRetryDelay.

NextRetryDelay przyjmuje jeden argument z typem RetryContext. Obiekt RetryContext ma trzy właściwości: PreviousRetryCount, ElapsedTime i RetryReason, które są longodpowiednio , i TimeSpanException . Przed pierwszą ponowną próbą nawiązania połączenia zarówno, jak PreviousRetryCount i ElapsedTime będzie zero, a RetryReason element będzie wyjątkiem, który spowodował utratę połączenia. Po każdej nieudanej próbie PreviousRetryCount ponawiania próby zostanie zwiększona o jeden, zostanie zaktualizowana tak, ElapsedTime aby odzwierciedlała ilość czasu spędzonego na ponownym połączeniu do tej pory i RetryReason będzie to wyjątek, który spowodował ostatnią ponowną próbę nawiązania połączenia.

NextRetryDelay Musi zwrócić przedział czasu reprezentujący czas oczekiwania przed kolejną ponowną próbą nawiązania połączenia lub null jeśli HubConnection element powinien przestać ponownie łączyć się.

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();

Alternatywnie możesz napisać kod, który ponownie połączy klienta ręcznie, jak pokazano w temacie Ręczne ponowne nawiązywanie połączenia.

Ręczne ponowne nawiązywanie połączenia

Ostrzeżenie

Przed wersją 3.0 klient SignalR platformy .NET nie łączy się automatycznie ponownie. Musisz napisać kod, który będzie ponownie łączyć klienta ręcznie.

Closed Użyj zdarzenia, aby odpowiedzieć na utracone połączenie. Na przykład możesz zautomatyzować ponowne nawiązywanie połączenia.

Zdarzenie Closed wymaga delegata zwracającego Taskelement , który umożliwia uruchamianie kodu asynchronicznego bez użycia polecenia async void. Aby spełnić wymagania podpisu delegata w procedurze Closed obsługi zdarzeń, która jest uruchamiana synchronicznie, zwróć polecenie Task.CompletedTask:

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

Główną przyczyną obsługi asynchronicznego jest możliwość ponownego uruchomienia połączenia. Uruchamianie połączenia jest akcją asynchroniczną.

Closed W programie obsługi, która uruchamia ponownie połączenie, rozważ oczekiwanie na pewne losowe opóźnienie, aby zapobiec przeciążeniu serwera, jak pokazano w poniższym przykładzie:

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

Metody centrum wywołań od klienta

InvokeAsync wywołuje metody w centrum. Przekaż nazwę metody centrum i wszystkie argumenty zdefiniowane w metodzie hub na InvokeAsync. SignalR jest asynchroniczna, więc użyj polecenia async i await podczas wykonywania wywołań.

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

Metoda InvokeAsync zwraca wartość Task , która kończy się po powrocie metody serwera. Wartość zwracana, jeśli istnieje, jest podana jako wynik .Task Wszelkie wyjątki zgłaszane przez metodę na serwerze generują błąd Task. Użyj await składni, aby poczekać na ukończenie metody serwera i try...catch składnię do obsługi błędów.

Metoda SendAsync zwraca element Task , który kończy się po wysłaniu komunikatu do serwera. Nie podano wartości zwracanej, ponieważ nie oczekuje ona Task na ukończenie metody serwera. Wszelkie wyjątki zgłaszane na kliencie podczas wysyłania komunikatu generują błąd Task. Używanie składni await i try...catch do obsługi błędów wysyłania.

Uwaga

Wywoływanie metod centrum od klienta jest obsługiwane tylko w przypadku korzystania z usługi platformy Azure SignalR w trybie domyślnym . Aby uzyskać więcej informacji, zobacz Często zadawane pytania (repozytorium GitHub azure-signalr).

Wywoływanie metod klienta z centrum

Zdefiniuj metody wywołania koncentratora przy użyciu polecenia connection.On po utworzeniu, ale przed rozpoczęciem połączenia.

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

Powyższy kod w programie connection.On jest uruchamiany, gdy kod po stronie serwera wywołuje go przy użyciu SendAsync metody .

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

Uwaga

Chociaż strona piasty połączenia obsługuje silnie typizowane komunikaty, klient musi zarejestrować się przy użyciu metody ogólnej z nazwą metody HubConnection.On . Aby zapoznać się z przykładem, zobacz Host ASP.NET Core SignalR w usługach w tle.

Obsługa błędów i rejestrowanie

Obsługa błędów za pomocą instrukcji try-catch. Sprawdź obiekt, Exception aby określić właściwą akcję do wykonania po wystąpieniu błędu.

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

Dodatkowe zasoby