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, voir Forum aux questions.
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
- Hubs
- Client JavaScript
- Publication dans Azure
- Documentation serverless du service SignalR Azure