Client .NET SignalR ASP.NET Core

La bibliothèque de client .NET SignalR ASP.NET Core vous permet de communiquer avec les hubs SignalR des applications .NET.

Affichez ou téléchargez l’exemple de code (procédure de téléchargement)

L’exemple de code de cet article est une application WPF qui utilise le client .NET SignalR ASP.NET Core.

Installer le package client .NET SignalR

Le package Microsoft.AspNetCore.SignalR.Client est requis pour permettre aux clients .NET de se connecter aux hubs SignalR.

Pour installer la bibliothèque de client, exécutez la commande suivante dans la Console du gestionnaire de package :

Install-Package Microsoft.AspNetCore.SignalR.Client

Se connecter à un hub

Pour établir une connexion, créez un HubConnectionBuilder et appelez Build. L’URL du hub, le protocole, le type de transport, le niveau du journal, les en-têtes et d’autres options peuvent être configurés lors de la création d’une connexion. Configurez toute option requise en insérant l'une des méthodes HubConnectionBuilder dans Build. Démarrez la connexion avec 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);                
            }
        }
    }
}

Gérer une connexion perdue

Se reconnecter automatiquement

La HubConnection peut être configurée pour se reconnecter automatiquement à l’aide de la méthode WithAutomaticReconnect sur le HubConnectionBuilder. Elle ne se reconnectera pas automatiquement par défaut.

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

Sans aucun paramètre, WithAutomaticReconnect() configure le client pour attendre 0, 2, 10 et 30 secondes respectivement avant chaque tentative de reconnexion. Il s'arrête après quatre tentatives échouées.

Avant de tenter quelconque reconnexion, la HubConnection passe à l’état HubConnectionState.Reconnecting et déclenche l’événement Reconnecting. Cela permet d'avertir les utilisateurs que la connexion a été perdue et de désactiver les éléments de l'IU. Les applications non interactives peuvent commencer à mettre des messages en file d’attente ou à les annuler.

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

Si le client se reconnecte avec succès lors de ses quatre premières tentatives, la HubConnection revient à l'état Connected et déclenche l’événement Reconnected. Cela permet d'informer les utilisateurs que la connexion a été rétablie et d’éliminer les messages dans la file d’attente.

Étant donné que la connexion paraît entièrement nouvelle pour le serveur, une nouvelle ConnectionId est fournie aux gestionnaires d'événements Reconnected.

Avertissement

Le paramètre connectionId du gestionnaire d’événements Reconnected sera nul si la HubConnection a été configurée pour ignorer la négociation.

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() ne configure pas la HubConnection pour retenter les échecs de démarrage initial. Les échecs de démarrage doivent donc être gérés manuellement :

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

Si le client ne parvient pas à se reconnecter lors de ses quatre premières tentatives, la HubConnection passe à l'état Disconnected et déclenche l’événement Closed. Cela permet de tenter le redémarrage manuel de la connexion ou d’informer les utilisateurs que la connexion est définitivement perdue.

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

Afin de configurer un nombre personnalisé de tentatives de reconnexion avant de se déconnecter ou de modifier le délai de reconnexion, WithAutomaticReconnect accepte un tableau de nombres représentant le délai d’attente en millisecondes avant de démarrer chaque tentative de reconnexion.

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.

L'exemple précédent configure le HubConnection pour qu'il commence à tenter des reconnexions immédiatement après la perte de la connexion. Ceci est également vrai pour la configuration par défaut.

Si la première tentative de reconnexion échoue, la deuxième tentative de reconnexion démarrera également immédiatement au lieu d'attendre 2 secondes comme dans la configuration par défaut.

Si la deuxième tentative de reconnexion échoue, la troisième tentative de reconnexion démarre après 10 secondes, encore comme dans la configuration par défaut.

Le comportement personnalisé s’écarte à nouveau du comportement par défaut en s’arrêtant après l’échec de la troisième tentative de reconnexion. La configuration par défaut lancerait une autre tentative de reconnexion après 30 secondes.

Si vous souhaitez encore plus de contrôle sur la synchronisation et le nombre de tentatives de reconnexion automatique, WithAutomaticReconnect accepte un objet qui implémente l'interface IRetryPolicy, laquelle a une seule méthode nommée NextRetryDelay.

NextRetryDelay prend un seul argument de type RetryContext. Le RetryContext a trois propriétés : PreviousRetryCount, ElapsedTime et RetryReason, qui sont respectivement un long, un TimeSpan et une Exception. Avant la première tentative de reconnexion, PreviousRetryCount et ElapsedTime sont à zéro, et la RetryReason est l’exception ayant entraîné la perte de la connexion. Après chaque tentative échouée, PreviousRetryCount est augmenté d’une unité, ElapsedTime est mis à jour pour illustrer le temps de reconnexion jusqu'à présent et RetryReason est l'exception ayant entraîné l'échec de la dernière tentative de reconnexion.

NextRetryDelay doit renvoyer soit un TimeSpan correspondant au temps d’attente avant la prochaine tentative de reconnexion, ou null si la HubConnection doit cesser de se reconnecter.

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

Vous pouvez également écrire du code qui reconnecte manuellement votre client, comme illustré dans Reconnexion manuelle.

Se reconnecter manuellement

Avertissement

Avant la version 3.0, le client .NET pour SignalR ne se reconnecte pas automatiquement. Vous devez écrire du code qui reconnecte manuellement votre client.

Utilisez l’événement Closed pour répondre à une connexion perdue. Par exemple, vous pouvez tenter d’automatiser la reconnexion.

L’événement Closed nécessite un délégué qui retourne une Task, permettant au code asynchrone de s’exécuter sans utiliser async void. Pour satisfaire la signature déléguée dans un gestionnaire d’événements Closed qui s’exécute de manière synchrone, retournez Task.CompletedTask :

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

La prise en charge asynchrone a pour motif principal le redémarrage de la connexion. Le démarrage d’une connexion est une action asynchrone.

Dans un gestionnaire Closed qui redémarre la connexion, envisagez d’attendre un délai aléatoire pour éviter la surcharge du serveur, comme illustré dans l’exemple suivant :

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

Appeler des méthodes hub à partir du client

InvokeAsync appelle des méthodes sur le hub. Transmettez le nom de la méthode hub et tout argument défini dans la méthode hub à InvokeAsync. SignalR étant asynchrone, utilisez async et await lors des appels.

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

La méthode InvokeAsync retourne une Task qui se termine lorsque la méthode serveur retourne. La valeur de retour, le cas échéant, est fournie en tant que résultat de la Task. Toutes les exceptions jetées par la méthode sur le serveur produisent une Task en défaut. Utilisez la syntaxe await pour attendre que la méthode serveur se termine et la syntaxe try...catch pour gérer les erreurs.

La méthode SendAsync retourne une Task qui se termine une fois le message envoyé au serveur. Aucune valeur de retour n’est fournie, car cette Task n’attend pas que la méthode serveur se termine. Toutes les exceptions jetées sur le client lors de l’envoi du message produisent une Task en défaut. Utilisez les syntaxes await et try...catch pour gérer les erreurs d’envoi.

Remarque

L'appel de méthodes de concentrateur à partir d'un client est uniquement pris en charge lors de l'utilisation du service SignalR Azure en mode par défaut. Pour plus d'informations, consultez Foire aux questions (dépôt GitHub azure-signalr).

Appeler des méthodes client depuis le hub

Définissez les méthodes appelées par le hub avec connection.On après la génération, mais avant de démarrer la connexion.

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

Le code précédent dans connection.On s'exécute lorsque le code côté serveur l'appelle à l'aide de la méthode SendAsync.

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

Remarque

Bien que le côté hub de la connexion prenne en charge la messagerie fortement typée, le client doit s’inscrire à l’aide de la méthode HubConnection.On générique avec le nom de la méthode. Pour voir un exemple, consultez Host ASP.NET Core SignalR dans les services en arrière-plan.

Gestion et journalisation des erreurs

Gérez les erreurs avec une instruction try-catch. Inspectez l’objet Exception pour déterminer l’action appropriée après qu’une erreur se produit.

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

Ressources supplémentaires