Utiliser des hubs SignalR pour ASP.NET Core
Par Rachel Appel et Kevin Griffin
L'API Hubs SignalR permet aux clients connectés d'appeler des méthodes sur le serveur, facilitant ainsi la communication en temps réel. Le serveur définit les méthodes appelées par le client et le client définit les méthodes appelées par le serveur. SignalR permet également une communication client à client indirecte et toujours modérée par le hub SignalR. Cela permet d’envoyer des messages entre des clients individuels, des groupes ou à tous les clients connectés. SignalR prend en charge tout ce qui est nécessaire pour rendre possible la communication client-serveur et serveur-client en temps réel.
Configurer les concentrateurs SignalR
Pour enregistrer les services requis par les hubs SignalR, appelez AddSignalR dans Program.cs
:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddSignalR();
Pour configurer les points de terminaison SignalR, appelez MapHub, également dans Program.cs
:
app.MapRazorPages();
app.MapHub<ChatHub>("/Chat");
app.Run();
Notes
Les assemblées côté serveur ASP.NET Core SignalR sont désormais installés avec le SDK .NET Core. Voir SignalR assemblées dans un framework partagé pour plus d'informations.
Créer et utiliser des hubs
Créez un hub en déclarant une classe qui hérite de Hub. Ajoutez des méthodes public
à la classe pour les rendre appelables depuis les clients :
public class ChatHub : Hub
{
public async Task SendMessage(string user, string message)
=> await Clients.All.SendAsync("ReceiveMessage", user, message);
}
Notes
Les hubs sont transitoires :
- Ne stockez pas l'état dans une propriété de la classe hub. Chaque appel de méthode hub est exécuté sur une nouvelle instance hub.
- N'instanciez pas un hub directement via l'injection de dépendances. Pour envoyer des messages à un client depuis un autre endroit de votre application, utilisez un fichier
IHubContext
. - À utiliser
await
lors de l'appel de méthodes asynchrones qui dépendent du maintien en vie du concentrateur. Par exemple, une méthode telle queClients.All.SendAsync(...)
peut échouer si elle est appelée sansawait
et si la méthode hub se termine avantSendAsync
finisse.
L'objet Contexte
La classe Hub inclut une propriété Context qui contient les propriétés suivantes avec des informations sur la connexion :
Propriété | Description |
---|---|
ConnectionId | Obtient l'ID unique de la connexion, attribué par SignalR. Il existe un ID de connexion pour chaque connexion. |
UserIdentifier | Obtient l'identifiant de l'utilisateur. Par défaut, SignalR utilise le ClaimTypes.NameIdentifier du ClaimsPrincipal associé à la connexion comme identifiant de l'utilisateur. |
User | Obtient le ClaimsPrincipal associé à l'utilisateur actuel. |
Items | Obtient une collection clé/valeur qui peut être utilisée pour partager des données dans le cadre de cette connexion. Les données peuvent être stockées dans cette collection et elles persisteront pour la connexion à travers différentes invocations de méthode de concentrateur. |
Features | Obtient la collection de fonctionnalités disponibles sur la connexion. Obtient la collection de fonctionnalités disponibles sur la connexion. |
ConnectionAborted | Obtient un CancellationToken qui notifie lorsque la connexion est interrompue. |
Hub.Context contient également les méthodes suivantes :
Méthode | Description |
---|---|
GetHttpContext | Renvoie le HttpContext pour la connexion, ou null si la connexion n'est pas associée à une requête HTTP. Pour les connexions HTTP, utilisez cette méthode pour obtenir des informations telles que les en-têtes HTTP et les chaînes de requête. |
Abort | Abandonne la connexion. |
L'objet Clients
La classeHub inclut une propriété Clients qui contient les propriétés suivantes pour la communication entre le serveur et le client :
Propriété | Description |
---|---|
All | Appelle une méthode sur tous les clients connectés |
Caller | Appelle une méthode sur le client qui a appelé la méthode hub |
Others | Appelle une méthode sur tous les clients connectés à l'exception du client qui a appelé la méthode |
Hub.Clients contient également les méthodes suivantes :
Méthode | Description |
---|---|
AllExcept | Appelle une méthode sur tous les clients connectés à l'exception des connexions spécifiées |
Client | Appelle une méthode sur un client connecté spécifique |
Clients | Appelle une méthode sur des clients connectés spécifiques |
Group | Appelle une méthode sur toutes les connexions du groupe spécifié |
GroupExcept | Appelle une méthode sur toutes les connexions du groupe spécifié, à l'exception des connexions spécifiées |
Groups | Appelle une méthode sur plusieurs groupes de connexions |
OthersInGroup | Appelle une méthode sur un groupe de connexions, à l'exclusion du client qui a appelé la méthode hub |
User | Appelle une méthode sur toutes les connexions associées à un utilisateur spécifique |
Users | Appelle une méthode sur toutes les connexions associées aux utilisateurs spécifiés |
Chaque propriété ou méthode des tableaux précédents renvoie un objet avec une méthode SendAsync
. La méthode SendAsync
reçoit le nom de la méthode cliente à appeler et les éventuels paramètres.
L'objet renvoyé par les méthodes Client
et Caller
contient également une méthode InvokeAsync
, qui peut être utilisée pour attendre un résultat du client.
Envoyer des messages aux clients
Pour appeler des clients spécifiques, utilisez les propriétés de l'objet Clients
. Dans l'exemple suivant, il existe trois méthodes de concentrateur :
SendMessage
envoie un message à tous les clients connectés, en utilisantClients.All
.SendMessageToCaller
renvoie un message à l'appelant en utilisantClients.Caller
.SendMessageToGroup
envoie un message à tous les clients du groupeSignalR Users
.
public async Task SendMessage(string user, string message)
=> await Clients.All.SendAsync("ReceiveMessage", user, message);
public async Task SendMessageToCaller(string user, string message)
=> await Clients.Caller.SendAsync("ReceiveMessage", user, message);
public async Task SendMessageToGroup(string user, string message)
=> await Clients.Group("SignalR Users").SendAsync("ReceiveMessage", user, message);
Hubs fortement typés
Un inconvénient de l'utilisation SendAsync
est qu'elle s'appuie sur une chaîne pour spécifier la méthode client à appeler. Cela laisse le code ouvert aux erreurs d'exécution si le nom de la méthode est mal orthographié ou absent du client.
Une alternative à l'utilisation SendAsync
consiste à taper fortement la classe Hub avec Hub<T>. Dans l'exemple suivant, la méthode client ChatHub
a été extraite dans une interface appelée IChatClient
:
public interface IChatClient
{
Task ReceiveMessage(string user, string message);
}
Cette interface peut être utilisée pour refactoriser l'exemple ChatHub
précédent pour qu'il soit fortement typé :
public class StronglyTypedChatHub : Hub<IChatClient>
{
public async Task SendMessage(string user, string message)
=> await Clients.All.ReceiveMessage(user, message);
public async Task SendMessageToCaller(string user, string message)
=> await Clients.Caller.ReceiveMessage(user, message);
public async Task SendMessageToGroup(string user, string message)
=> await Clients.Group("SignalR Users").ReceiveMessage(user, message);
}
L'utilisation Hub<IChatClient>
active la vérification au moment de la compilation des méthodes client. Cela évite les problèmes causés par l'utilisation de chaînes, car Hub<T>
ne peut donner accès qu'aux méthodes définies dans l'interface. L'utilisation d'un type fortement Hub<T>
désactivé désactive la possibilité d'utiliser SendAsync
.
Notes
Le suffixe Async
n'est pas supprimé des noms de méthodes. À moins qu'une méthode client ne soit définie avec .on('MyMethodAsync')
, ne l'utilisez pas MyMethodAsync
comme nom.
Résultats du client
En plus d'appeler les clients, le serveur peut demander un résultat à un client. Cela nécessite que le serveur utilise ISingleClientProxy.InvokeAsync
et que le client retourne un résultat à partir de son gestionnaire .On
.
Il existe deux manières d'utiliser l'API sur le serveur, la première consiste à appeler Client(...)
ou Caller
sur la propriété Clients
dans une méthode Hub :
public class ChatHub : Hub
{
public async Task<string> WaitForMessage(string connectionId)
{
var message = await Clients.Client(connectionId).InvokeAsync<string>(
"GetMessage");
return message;
}
}
La deuxième façon est d'appeler Client(...)
sur une instance de IHubContext<T>
:
async Task SomeMethod(IHubContext<MyHub> context)
{
string result = await context.Clients.Client(connectionID).InvokeAsync<string>(
"GetMessage");
}
Les concentrateurs fortement typés peuvent également renvoyer des valeurs à partir de méthodes d'interface :
public interface IClient
{
Task<string> GetMessage();
}
public class ChatHub : Hub<IClient>
{
public async Task<string> WaitForMessage(string connectionId)
{
string message = await Clients.Client(connectionId).GetMessage();
return message;
}
}
Les clients renvoient les résultats dans leurs gestionnaires .On(...)
, comme indiqué ci-dessous :
Client .NET
hubConnection.On("GetMessage", async () =>
{
Console.WriteLine("Enter message:");
var message = await Console.In.ReadLineAsync();
return message;
});
Client dactylographié
hubConnection.on("GetMessage", async () => {
let promise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("message");
}, 100);
});
return promise;
});
Client Java
hubConnection.onWithResult("GetMessage", () -> {
return Single.just("message");
});
Changer le nom d'une méthode hub
Par défaut, un nom de méthode de hub de serveur est le nom de la méthode .NET. Pour modifier ce comportement par défaut pour une méthode spécifique, utilisez l'attribut HubMethodName. Le client doit utiliser ce nom au lieu du nom de la méthode .NET lors de l'appel de la méthode :
[HubMethodName("SendMessageToUser")]
public async Task DirectMessage(string user, string message)
=> await Clients.User(user).SendAsync("ReceiveMessage", user, message);
Injecter des services dans un hub
Les constructeurs de hub peuvent accepter les services de DI en tant que paramètres, qui peuvent être stockés dans des propriétés sur la classe pour une utilisation dans une méthode de hub.
Lors de l'injection de plusieurs services pour différentes méthodes de concentrateur ou comme méthode alternative d'écriture de code, les méthodes de concentrateur peuvent également accepter des services de DI. Par défaut, les paramètres de la méthode hub sont inspectés et résolus à partir de DI si possible.
services.AddSingleton<IDatabaseService, DatabaseServiceImpl>();
// ...
public class ChatHub : Hub
{
public Task SendMessage(string user, string message, IDatabaseService dbService)
{
var userName = dbService.GetUserName(user);
return Clients.All.SendAsync("ReceiveMessage", userName, message);
}
}
Si la résolution implicite des paramètres des services n'est pas souhaitée, désactivez-la avec DisableImplicitFromServicesParameters.
Pour spécifier explicitement quels paramètres sont résolus à partir de DI dans les méthodes de concentrateur, utilisez l'option DisableImplicitFromServicesParameters
et utilisez l'attribut [FromServices]
ou un attribut personnalisé qui implémente IFromServiceMetadata
sur les paramètres de méthode de concentrateur qui doivent être résolus à partir de DI.
services.AddSingleton<IDatabaseService, DatabaseServiceImpl>();
services.AddSignalR(options =>
{
options.DisableImplicitFromServicesParameters = true;
});
// ...
public class ChatHub : Hub
{
public Task SendMessage(string user, string message,
[FromServices] IDatabaseService dbService)
{
var userName = dbService.GetUserName(user);
return Clients.All.SendAsync("ReceiveMessage", userName, message);
}
}
Notes
Cette fonctionnalité utilise IServiceProviderIsService, qui est éventuellement implémenté par les implémentations DI. Si le conteneur DI de l'application ne prend pas en charge cette fonctionnalité, l'injection de services dans les méthodes de concentrateur n'est pas prise en charge.
Prise en charge des services à clé dans l’injection de dépendances
Les services à clé désigne un mécanisme d’inscription et de récupération des services d’injection de dépendances (DI) à l’aide de clés. Un service est associé à une clé en appelant AddKeyedSingleton (ou AddKeyedScoped
ou AddKeyedTransient
) pour l’inscrire. Accédez à un service inscrit en spécifiant la clé avec l’attribut [FromKeyedServices]
. Le code suivant montre comment utiliser les services à clé :
using Microsoft.AspNetCore.SignalR;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddKeyedSingleton<ICache, BigCache>("big");
builder.Services.AddKeyedSingleton<ICache, SmallCache>("small");
builder.Services.AddRazorPages();
builder.Services.AddSignalR();
var app = builder.Build();
app.MapRazorPages();
app.MapHub<MyHub>("/myHub");
app.Run();
public interface ICache
{
object Get(string key);
}
public class BigCache : ICache
{
public object Get(string key) => $"Resolving {key} from big cache.";
}
public class SmallCache : ICache
{
public object Get(string key) => $"Resolving {key} from small cache.";
}
public class MyHub : Hub
{
public void SmallCacheMethod([FromKeyedServices("small")] ICache cache)
{
Console.WriteLine(cache.Get("signalr"));
}
public void BigCacheMethod([FromKeyedServices("big")] ICache cache)
{
Console.WriteLine(cache.Get("signalr"));
}
}
Gérer les événements d'une connexion
L'API Hubs SignalR fournit les méthodes virtuelles OnConnectedAsync et OnDisconnectedAsync pour gérer et suivre les connexions. Remplacez la méthode virtuelle OnConnectedAsync
pour effectuer des actions lorsqu'un client se connecte au hub, comme l'ajouter à un groupe :
public override async Task OnConnectedAsync()
{
await Groups.AddToGroupAsync(Context.ConnectionId, "SignalR Users");
await base.OnConnectedAsync();
}
Remplacez la méthode virtuelle OnDisconnectedAsync
pour effectuer des actions lorsqu'un client se déconnecte. Si le client se déconnecte intentionnellement connection.stop()
, par exemple en appelant exception
, le paramètre est défini sur null
. Cependant, si le client se déconnecte en raison d'une erreur, telle qu'une panne de réseau, le paramètre exception
contient une exception qui décrit la panne :
public override async Task OnDisconnectedAsync(Exception? exception)
{
await base.OnDisconnectedAsync(exception);
}
RemoveFromGroupAsync n’a pas besoin d’être appelé dans OnDisconnectedAsync, il est automatiquement géré pour vous.
Gérer les erreurs
Les exceptions levées dans les méthodes du concentrateur sont envoyées au client qui a appelé la méthode. Sur le client JavaScript, la méthode invoke
renvoie un JavaScript Promise
. Les clients peuvent attacher un gestionnaire catch
à la promesse retournée ou utiliser try
/catch
avec async
/await
pour gérer les exceptions :
try {
await connection.invoke("SendMessage", user, message);
} catch (err) {
console.error(err);
}
Les connexions ne sont pas fermées lorsqu'un concentrateur lève une exception. Par défaut, SignalR renvoie un message d'erreur générique au client, comme illustré dans l'exemple suivant :
Microsoft.AspNetCore.SignalR.HubException: An unexpected error occurred invoking 'SendMessage' on the server.
’Les exceptions inattendues contiennent souvent des informations sensibles, telles que le nom d'un serveur de base de données dans une exception déclenchée lorsque la connexion aux bases de données échoue. SignalR n'expose pas ces messages d'erreur détaillés par défaut par mesure de sécurité. Pour plus d'informations sur la raison pour laquelle les détails de l'exception sont supprimés, consultez Considérations sur la sécurité dans ASP.NET Core SignalR.
Si une condition exceptionnelle doit être propagée au client, utilisez la classe HubException. Si un HubException
est lancé dans une méthode hub, SignalRenvoie l'intégralité du message d'exception au client, non modifié :
public Task ThrowException()
=> throw new HubException("This error will be sent to the client!");
Notes
SignalR envoie uniquement la propriété Message
de l'exception au client. La trace de la pile et les autres propriétés de l'exception ne sont pas disponibles pour le client.
Ressources supplémentaires
Par Rachel Appel et Kevin Griffin
L'API Hubs SignalR permet aux clients connectés d'appeler des méthodes sur le serveur, facilitant ainsi la communication en temps réel. Le serveur définit les méthodes appelées par le client et le client définit les méthodes appelées par le serveur. SignalR permet également une communication client à client indirecte et toujours modérée par le hub SignalR. Cela permet d’envoyer des messages entre des clients individuels, des groupes ou à tous les clients connectés. SignalR prend en charge tout ce qui est nécessaire pour rendre possible la communication client-serveur et serveur-client en temps réel.
Configurer les concentrateurs SignalR
Pour enregistrer les services requis par les hubs SignalR, appelez AddSignalR dans Program.cs
:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddSignalR();
Pour configurer les points de terminaison SignalR, appelez MapHub, également dans Program.cs
:
app.MapRazorPages();
app.MapHub<ChatHub>("/Chat");
app.Run();
Notes
Les assemblées côté serveur ASP.NET Core SignalR sont désormais installés avec le SDK .NET Core. Voir SignalR assemblées dans un framework partagé pour plus d'informations.
Créer et utiliser des hubs
Créez un hub en déclarant une classe qui hérite de Hub. Ajoutez des méthodes public
à la classe pour les rendre appelables depuis les clients :
public class ChatHub : Hub
{
public async Task SendMessage(string user, string message)
=> await Clients.All.SendAsync("ReceiveMessage", user, message);
}
Notes
Les hubs sont transitoires :
- Ne stockez pas l'état dans une propriété de la classe hub. Chaque appel de méthode hub est exécuté sur une nouvelle instance hub.
- N'instanciez pas un hub directement via l'injection de dépendances. Pour envoyer des messages à un client depuis un autre endroit de votre application, utilisez un fichier
IHubContext
. - À utiliser
await
lors de l'appel de méthodes asynchrones qui dépendent du maintien en vie du concentrateur. Par exemple, une méthode telle queClients.All.SendAsync(...)
peut échouer si elle est appelée sansawait
et si la méthode hub se termine avantSendAsync
finisse.
L'objet Contexte
La classe Hub inclut une propriété Context qui contient les propriétés suivantes avec des informations sur la connexion :
Propriété | Description |
---|---|
ConnectionId | Obtient l'ID unique de la connexion, attribué par SignalR. Il existe un ID de connexion pour chaque connexion. |
UserIdentifier | Obtient l'identifiant de l'utilisateur. Par défaut, SignalR utilise le ClaimTypes.NameIdentifier du ClaimsPrincipal associé à la connexion comme identifiant de l'utilisateur. |
User | Obtient le ClaimsPrincipal associé à l'utilisateur actuel. |
Items | Obtient une collection clé/valeur qui peut être utilisée pour partager des données dans le cadre de cette connexion. Les données peuvent être stockées dans cette collection et elles persisteront pour la connexion à travers différentes invocations de méthode de concentrateur. |
Features | Obtient la collection de fonctionnalités disponibles sur la connexion. Obtient la collection de fonctionnalités disponibles sur la connexion. |
ConnectionAborted | Obtient un CancellationToken qui notifie lorsque la connexion est interrompue. |
Hub.Context contient également les méthodes suivantes :
Méthode | Description |
---|---|
GetHttpContext | Renvoie le HttpContext pour la connexion, ou null si la connexion n'est pas associée à une requête HTTP. Pour les connexions HTTP, utilisez cette méthode pour obtenir des informations telles que les en-têtes HTTP et les chaînes de requête. |
Abort | Abandonne la connexion. |
L'objet Clients
La classeHub inclut une propriété Clients qui contient les propriétés suivantes pour la communication entre le serveur et le client :
Propriété | Description |
---|---|
All | Appelle une méthode sur tous les clients connectés |
Caller | Appelle une méthode sur le client qui a appelé la méthode hub |
Others | Appelle une méthode sur tous les clients connectés à l'exception du client qui a appelé la méthode |
Hub.Clients contient également les méthodes suivantes :
Méthode | Description |
---|---|
AllExcept | Appelle une méthode sur tous les clients connectés à l'exception des connexions spécifiées |
Client | Appelle une méthode sur un client connecté spécifique |
Clients | Appelle une méthode sur des clients connectés spécifiques |
Group | Appelle une méthode sur toutes les connexions du groupe spécifié |
GroupExcept | Appelle une méthode sur toutes les connexions du groupe spécifié, à l'exception des connexions spécifiées |
Groups | Appelle une méthode sur plusieurs groupes de connexions |
OthersInGroup | Appelle une méthode sur un groupe de connexions, à l'exclusion du client qui a appelé la méthode hub |
User | Appelle une méthode sur toutes les connexions associées à un utilisateur spécifique |
Users | Appelle une méthode sur toutes les connexions associées aux utilisateurs spécifiés |
Chaque propriété ou méthode des tableaux précédents renvoie un objet avec une méthode SendAsync
. La méthode SendAsync
reçoit le nom de la méthode cliente à appeler et les éventuels paramètres.
L'objet renvoyé par les méthodes Client
et Caller
contient également une méthode InvokeAsync
, qui peut être utilisée pour attendre un résultat du client.
Envoyer des messages aux clients
Pour appeler des clients spécifiques, utilisez les propriétés de l'objet Clients
. Dans l'exemple suivant, il existe trois méthodes de concentrateur :
SendMessage
envoie un message à tous les clients connectés, en utilisantClients.All
.SendMessageToCaller
renvoie un message à l'appelant en utilisantClients.Caller
.SendMessageToGroup
envoie un message à tous les clients du groupeSignalR Users
.
public async Task SendMessage(string user, string message)
=> await Clients.All.SendAsync("ReceiveMessage", user, message);
public async Task SendMessageToCaller(string user, string message)
=> await Clients.Caller.SendAsync("ReceiveMessage", user, message);
public async Task SendMessageToGroup(string user, string message)
=> await Clients.Group("SignalR Users").SendAsync("ReceiveMessage", user, message);
Hubs fortement typés
Un inconvénient de l'utilisation SendAsync
est qu'elle s'appuie sur une chaîne pour spécifier la méthode client à appeler. Cela laisse le code ouvert aux erreurs d'exécution si le nom de la méthode est mal orthographié ou absent du client.
Une alternative à l'utilisation SendAsync
consiste à taper fortement la classe Hub avec Hub<T>. Dans l'exemple suivant, la méthode client ChatHub
a été extraite dans une interface appelée IChatClient
:
public interface IChatClient
{
Task ReceiveMessage(string user, string message);
}
Cette interface peut être utilisée pour refactoriser l'exemple ChatHub
précédent pour qu'il soit fortement typé :
public class StronglyTypedChatHub : Hub<IChatClient>
{
public async Task SendMessage(string user, string message)
=> await Clients.All.ReceiveMessage(user, message);
public async Task SendMessageToCaller(string user, string message)
=> await Clients.Caller.ReceiveMessage(user, message);
public async Task SendMessageToGroup(string user, string message)
=> await Clients.Group("SignalR Users").ReceiveMessage(user, message);
}
L'utilisation Hub<IChatClient>
active la vérification au moment de la compilation des méthodes client. Cela évite les problèmes causés par l'utilisation de chaînes, car Hub<T>
ne peut donner accès qu'aux méthodes définies dans l'interface. L'utilisation d'un type fortement Hub<T>
désactivé désactive la possibilité d'utiliser SendAsync
.
Notes
Le suffixe Async
n'est pas supprimé des noms de méthodes. À moins qu'une méthode client ne soit définie avec .on('MyMethodAsync')
, ne l'utilisez pas MyMethodAsync
comme nom.
Résultats du client
En plus d'appeler les clients, le serveur peut demander un résultat à un client. Cela nécessite que le serveur utilise ISingleClientProxy.InvokeAsync
et que le client retourne un résultat à partir de son gestionnaire .On
.
Il existe deux manières d'utiliser l'API sur le serveur, la première consiste à appeler Client(...)
ou Caller
sur la propriété Clients
dans une méthode Hub :
public class ChatHub : Hub
{
public async Task<string> WaitForMessage(string connectionId)
{
var message = await Clients.Client(connectionId).InvokeAsync<string>(
"GetMessage");
return message;
}
}
La deuxième façon est d'appeler Client(...)
sur une instance de IHubContext<T>
:
async Task SomeMethod(IHubContext<MyHub> context)
{
string result = await context.Clients.Client(connectionID).InvokeAsync<string>(
"GetMessage");
}
Les concentrateurs fortement typés peuvent également renvoyer des valeurs à partir de méthodes d'interface :
public interface IClient
{
Task<string> GetMessage();
}
public class ChatHub : Hub<IClient>
{
public async Task<string> WaitForMessage(string connectionId)
{
string message = await Clients.Client(connectionId).GetMessage();
return message;
}
}
Les clients renvoient les résultats dans leurs gestionnaires .On(...)
, comme indiqué ci-dessous :
Client .NET
hubConnection.On("GetMessage", async () =>
{
Console.WriteLine("Enter message:");
var message = await Console.In.ReadLineAsync();
return message;
});
Client dactylographié
hubConnection.on("GetMessage", async () => {
let promise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("message");
}, 100);
});
return promise;
});
Client Java
hubConnection.onWithResult("GetMessage", () -> {
return Single.just("message");
});
Changer le nom d'une méthode hub
Par défaut, un nom de méthode de hub de serveur est le nom de la méthode .NET. Pour modifier ce comportement par défaut pour une méthode spécifique, utilisez l'attribut HubMethodName. Le client doit utiliser ce nom au lieu du nom de la méthode .NET lors de l'appel de la méthode :
[HubMethodName("SendMessageToUser")]
public async Task DirectMessage(string user, string message)
=> await Clients.User(user).SendAsync("ReceiveMessage", user, message);
Injecter des services dans un hub
Les constructeurs de hub peuvent accepter les services de DI en tant que paramètres, qui peuvent être stockés dans des propriétés sur la classe pour une utilisation dans une méthode de hub.
Lors de l'injection de plusieurs services pour différentes méthodes de concentrateur ou comme méthode alternative d'écriture de code, les méthodes de concentrateur peuvent également accepter des services de DI. Par défaut, les paramètres de la méthode hub sont inspectés et résolus à partir de DI si possible.
services.AddSingleton<IDatabaseService, DatabaseServiceImpl>();
// ...
public class ChatHub : Hub
{
public Task SendMessage(string user, string message, IDatabaseService dbService)
{
var userName = dbService.GetUserName(user);
return Clients.All.SendAsync("ReceiveMessage", userName, message);
}
}
Si la résolution implicite des paramètres des services n'est pas souhaitée, désactivez-la avec DisableImplicitFromServicesParameters.
Pour spécifier explicitement quels paramètres sont résolus à partir de DI dans les méthodes de concentrateur, utilisez l'option DisableImplicitFromServicesParameters
et utilisez l'attribut [FromServices]
ou un attribut personnalisé qui implémente IFromServiceMetadata
sur les paramètres de méthode de concentrateur qui doivent être résolus à partir de DI.
services.AddSingleton<IDatabaseService, DatabaseServiceImpl>();
services.AddSignalR(options =>
{
options.DisableImplicitFromServicesParameters = true;
});
// ...
public class ChatHub : Hub
{
public Task SendMessage(string user, string message,
[FromServices] IDatabaseService dbService)
{
var userName = dbService.GetUserName(user);
return Clients.All.SendAsync("ReceiveMessage", userName, message);
}
}
Notes
Cette fonctionnalité utilise IServiceProviderIsService, qui est éventuellement implémenté par les implémentations DI. Si le conteneur DI de l'application ne prend pas en charge cette fonctionnalité, l'injection de services dans les méthodes de concentrateur n'est pas prise en charge.
Gérer les événements d'une connexion
L'API Hubs SignalR fournit les méthodes virtuelles OnConnectedAsync et OnDisconnectedAsync pour gérer et suivre les connexions. Remplacez la méthode virtuelle OnConnectedAsync
pour effectuer des actions lorsqu'un client se connecte au hub, comme l'ajouter à un groupe :
public override async Task OnConnectedAsync()
{
await Groups.AddToGroupAsync(Context.ConnectionId, "SignalR Users");
await base.OnConnectedAsync();
}
Remplacez la méthode virtuelle OnDisconnectedAsync
pour effectuer des actions lorsqu'un client se déconnecte. Si le client se déconnecte intentionnellement connection.stop()
, par exemple en appelant exception
, le paramètre est défini sur null
. Cependant, si le client se déconnecte en raison d'une erreur, telle qu'une panne de réseau, le paramètre exception
contient une exception qui décrit la panne :
public override async Task OnDisconnectedAsync(Exception? exception)
{
await base.OnDisconnectedAsync(exception);
}
RemoveFromGroupAsync n'a pas besoin d'être appelé OnDisconnectedAsync, il est automatiquement géré pour vous.
Gérer les erreurs
Les exceptions levées dans les méthodes du concentrateur sont envoyées au client qui a appelé la méthode. Sur le client JavaScript, la méthode invoke
renvoie un JavaScript Promise
. Les clients peuvent attacher un gestionnaire catch
à la promesse retournée ou utiliser try
/catch
avec async
/await
pour gérer les exceptions :
try {
await connection.invoke("SendMessage", user, message);
} catch (err) {
console.error(err);
}
Les connexions ne sont pas fermées lorsqu'un concentrateur lève une exception. Par défaut, SignalR renvoie un message d'erreur générique au client, comme illustré dans l'exemple suivant :
Microsoft.AspNetCore.SignalR.HubException: An unexpected error occurred invoking 'SendMessage' on the server.
’Les exceptions inattendues contiennent souvent des informations sensibles, telles que le nom d'un serveur de base de données dans une exception déclenchée lorsque la connexion aux bases de données échoue. SignalR n'expose pas ces messages d'erreur détaillés par défaut par mesure de sécurité. Pour plus d'informations sur la raison pour laquelle les détails de l'exception sont supprimés, consultez Considérations sur la sécurité dans ASP.NET Core SignalR.
Si une condition exceptionnelle doit être propagée au client, utilisez la classe HubException. Si un HubException
est lancé dans une méthode hub, SignalRenvoie l'intégralité du message d'exception au client, non modifié :
public Task ThrowException()
=> throw new HubException("This error will be sent to the client!");
Notes
SignalR envoie uniquement la propriété Message
de l'exception au client. La trace de la pile et les autres propriétés de l'exception ne sont pas disponibles pour le client.
Ressources supplémentaires
Par Rachel Appel et Kevin Griffin
L'API Hubs SignalR permet aux clients connectés d'appeler des méthodes sur le serveur, facilitant ainsi la communication en temps réel. Le serveur définit les méthodes appelées par le client et le client définit les méthodes appelées par le serveur. SignalR permet également une communication client à client indirecte et toujours modérée par le hub SignalR. Cela permet d’envoyer des messages entre des clients individuels, des groupes ou à tous les clients connectés. SignalR prend en charge tout ce qui est nécessaire pour rendre possible la communication client-serveur et serveur-client en temps réel.
Configurer les concentrateurs SignalR
Pour enregistrer les services requis par les hubs SignalR, appelez AddSignalR dans Program.cs
:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddSignalR();
Pour configurer les points de terminaison SignalR, appelez MapHub, également dans Program.cs
:
app.MapRazorPages();
app.MapHub<ChatHub>("/Chat");
app.Run();
Notes
Les assemblées côté serveur ASP.NET Core SignalR sont désormais installés avec le SDK .NET Core. Voir SignalR assemblées dans un framework partagé pour plus d'informations.
Créer et utiliser des hubs
Créez un hub en déclarant une classe qui hérite de Hub. Ajoutez des méthodes public
à la classe pour les rendre appelables depuis les clients :
public class ChatHub : Hub
{
public async Task SendMessage(string user, string message)
=> await Clients.All.SendAsync("ReceiveMessage", user, message);
}
Notes
Les hubs sont transitoires :
- Ne stockez pas l'état dans une propriété de la classe hub. Chaque appel de méthode hub est exécuté sur une nouvelle instance hub.
- N'instanciez pas un hub directement via l'injection de dépendances. Pour envoyer des messages à un client depuis un autre endroit de votre application, utilisez un fichier
IHubContext
. - À utiliser
await
lors de l'appel de méthodes asynchrones qui dépendent du maintien en vie du concentrateur. Par exemple, une méthode telle queClients.All.SendAsync(...)
peut échouer si elle est appelée sansawait
et si la méthode hub se termine avantSendAsync
finisse.
L'objet Contexte
La classe Hub inclut une propriété Context qui contient les propriétés suivantes avec des informations sur la connexion :
Propriété | Description |
---|---|
ConnectionId | Obtient l'ID unique de la connexion, attribué par SignalR. Il existe un ID de connexion pour chaque connexion. |
UserIdentifier | Obtient l'identifiant de l'utilisateur. Par défaut, SignalR utilise le ClaimTypes.NameIdentifier du ClaimsPrincipal associé à la connexion comme identifiant de l'utilisateur. |
User | Obtient le ClaimsPrincipal associé à l'utilisateur actuel. |
Items | Obtient une collection clé/valeur qui peut être utilisée pour partager des données dans le cadre de cette connexion. Les données peuvent être stockées dans cette collection et elles persisteront pour la connexion à travers différentes invocations de méthode de concentrateur. |
Features | Obtient la collection de fonctionnalités disponibles sur la connexion. Obtient la collection de fonctionnalités disponibles sur la connexion. |
ConnectionAborted | Obtient un CancellationToken qui notifie lorsque la connexion est interrompue. |
Hub.Context contient également les méthodes suivantes :
Méthode | Description |
---|---|
GetHttpContext | Renvoie le HttpContext pour la connexion, ou null si la connexion n'est pas associée à une requête HTTP. Pour les connexions HTTP, utilisez cette méthode pour obtenir des informations telles que les en-têtes HTTP et les chaînes de requête. |
Abort | Abandonne la connexion. |
L'objet Clients
La classeHub inclut une propriété Clients qui contient les propriétés suivantes pour la communication entre le serveur et le client :
Propriété | Description |
---|---|
All | Appelle une méthode sur tous les clients connectés |
Caller | Appelle une méthode sur le client qui a appelé la méthode hub |
Others | Appelle une méthode sur tous les clients connectés à l'exception du client qui a appelé la méthode |
Hub.Clients contient également les méthodes suivantes :
Méthode | Description |
---|---|
AllExcept | Appelle une méthode sur tous les clients connectés à l'exception des connexions spécifiées |
Client | Appelle une méthode sur un client connecté spécifique |
Clients | Appelle une méthode sur des clients connectés spécifiques |
Group | Appelle une méthode sur toutes les connexions du groupe spécifié |
GroupExcept | Appelle une méthode sur toutes les connexions du groupe spécifié, à l'exception des connexions spécifiées |
Groups | Appelle une méthode sur plusieurs groupes de connexions |
OthersInGroup | Appelle une méthode sur un groupe de connexions, à l'exclusion du client qui a appelé la méthode hub |
User | Appelle une méthode sur toutes les connexions associées à un utilisateur spécifique |
Users | Appelle une méthode sur toutes les connexions associées aux utilisateurs spécifiés |
Chaque propriété ou méthode des tableaux précédents renvoie un objet avec une méthode SendAsync
. La méthode SendAsync
reçoit le nom de la méthode cliente à appeler et les éventuels paramètres.
Envoyer des messages aux clients
Pour appeler des clients spécifiques, utilisez les propriétés de l'objet Clients
. Dans l'exemple suivant, il existe trois méthodes de concentrateur :
SendMessage
envoie un message à tous les clients connectés, en utilisantClients.All
.SendMessageToCaller
renvoie un message à l'appelant en utilisantClients.Caller
.SendMessageToGroup
envoie un message à tous les clients du groupeSignalR Users
.
public async Task SendMessage(string user, string message)
=> await Clients.All.SendAsync("ReceiveMessage", user, message);
public async Task SendMessageToCaller(string user, string message)
=> await Clients.Caller.SendAsync("ReceiveMessage", user, message);
public async Task SendMessageToGroup(string user, string message)
=> await Clients.Group("SignalR Users").SendAsync("ReceiveMessage", user, message);
Hubs fortement typés
Un inconvénient de l'utilisation SendAsync
est qu'elle s'appuie sur une chaîne pour spécifier la méthode client à appeler. Cela laisse le code ouvert aux erreurs d'exécution si le nom de la méthode est mal orthographié ou absent du client.
Une alternative à l'utilisation SendAsync
consiste à taper fortement la classe Hub avec Hub<T>. Dans l'exemple suivant, la méthode client ChatHub
a été extraite dans une interface appelée IChatClient
:
public interface IChatClient
{
Task ReceiveMessage(string user, string message);
}
Cette interface peut être utilisée pour refactoriser l'exemple ChatHub
précédent pour qu'il soit fortement typé :
public class StronglyTypedChatHub : Hub<IChatClient>
{
public async Task SendMessage(string user, string message)
=> await Clients.All.ReceiveMessage(user, message);
public async Task SendMessageToCaller(string user, string message)
=> await Clients.Caller.ReceiveMessage(user, message);
public async Task SendMessageToGroup(string user, string message)
=> await Clients.Group("SignalR Users").ReceiveMessage(user, message);
}
L'utilisation Hub<IChatClient>
active la vérification au moment de la compilation des méthodes client. Cela évite les problèmes causés par l'utilisation de chaînes, car Hub<T>
ne peut donner accès qu'aux méthodes définies dans l'interface. L'utilisation d'un type fortement Hub<T>
désactivé désactive la possibilité d'utiliser SendAsync
.
Notes
Le suffixe Async
n'est pas supprimé des noms de méthodes. À moins qu'une méthode client ne soit définie avec .on('MyMethodAsync')
, ne l'utilisez pas MyMethodAsync
comme nom.
Changer le nom d'une méthode hub
Par défaut, un nom de méthode de hub de serveur est le nom de la méthode .NET. Pour modifier ce comportement par défaut pour une méthode spécifique, utilisez l'attribut HubMethodName. Le client doit utiliser ce nom au lieu du nom de la méthode .NET lors de l'appel de la méthode :
[HubMethodName("SendMessageToUser")]
public async Task DirectMessage(string user, string message)
=> await Clients.User(user).SendAsync("ReceiveMessage", user, message);
Gérer les événements d'une connexion
L'API Hubs SignalR fournit les méthodes virtuelles OnConnectedAsync et OnDisconnectedAsync pour gérer et suivre les connexions. Remplacez la méthode virtuelle OnConnectedAsync
pour effectuer des actions lorsqu'un client se connecte au hub, comme l'ajouter à un groupe :
public override async Task OnConnectedAsync()
{
await Groups.AddToGroupAsync(Context.ConnectionId, "SignalR Users");
await base.OnConnectedAsync();
}
Remplacez la méthode virtuelle OnDisconnectedAsync
pour effectuer des actions lorsqu'un client se déconnecte. Si le client se déconnecte intentionnellement connection.stop()
, par exemple en appelant exception
, le paramètre est défini sur null
. Cependant, si le client se déconnecte en raison d'une erreur, telle qu'une panne de réseau, le paramètre exception
contient une exception qui décrit la panne :
public override async Task OnDisconnectedAsync(Exception? exception)
{
await base.OnDisconnectedAsync(exception);
}
RemoveFromGroupAsync n'a pas besoin d'être appelé OnDisconnectedAsync, il est automatiquement géré pour vous.
Gérer les erreurs
Les exceptions levées dans les méthodes du concentrateur sont envoyées au client qui a appelé la méthode. Sur le client JavaScript, la méthode invoke
renvoie un JavaScript Promise
. Les clients peuvent attacher un gestionnaire catch
à la promesse retournée ou utiliser try
/catch
avec async
/await
pour gérer les exceptions :
try {
await connection.invoke("SendMessage", user, message);
} catch (err) {
console.error(err);
}
Les connexions ne sont pas fermées lorsqu'un concentrateur lève une exception. Par défaut, SignalR renvoie un message d'erreur générique au client, comme illustré dans l'exemple suivant :
Microsoft.AspNetCore.SignalR.HubException: An unexpected error occurred invoking 'SendMessage' on the server.
’Les exceptions inattendues contiennent souvent des informations sensibles, telles que le nom d'un serveur de base de données dans une exception déclenchée lorsque la connexion aux bases de données échoue. SignalR n'expose pas ces messages d'erreur détaillés par défaut par mesure de sécurité. Pour plus d'informations sur la raison pour laquelle les détails de l'exception sont supprimés, consultez Considérations sur la sécurité dans ASP.NET Core SignalR.
Si une condition exceptionnelle doit être propagée au client, utilisez la classe HubException. Si un HubException
est lancé dans une méthode hub, SignalRenvoie l'intégralité du message d'exception au client, non modifié :
public Task ThrowException()
=> throw new HubException("This error will be sent to the client!");
Notes
SignalR envoie uniquement la propriété Message
de l'exception au client. La trace de la pile et les autres propriétés de l'exception ne sont pas disponibles pour le client.
Ressources supplémentaires
Par Rachel Appel et Kevin Griffin
Affichez ou téléchargez l’exemple de code (procédure de téléchargement)
Qu'est-ce qu'un hub SignalR
L'API Hubs SignalR permet aux clients connectés d'appeler des méthodes sur le serveur, facilitant ainsi la communication en temps réel. Le serveur définit les méthodes appelées par le client et le client définit les méthodes appelées par le serveur. SignalR permet également une communication client à client indirecte et toujours modérée par le hub SignalR. Cela permet d’envoyer des messages entre des clients individuels, des groupes ou à tous les clients connectés. SignalR prend en charge tout ce qui est nécessaire pour rendre possible la communication client-serveur et serveur-client en temps réel.
Configurer les concentrateurs SignalR
Le middleware SignalR nécessite certains services, qui se configurent en appelant AddSignalR :
services.AddSignalR();
Lors de l'ajout de fonctionnalité SignalR à une application ASP.NET Core, configurez les routes SignalR en appelant MapHub le Startup.Configure
rappel de UseEndpoints la méthode :
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapHub<ChatHub>("/chathub");
});
Notes
Les assemblées côté serveur ASP.NET Core SignalR sont désormais installés avec le SDK .NET Core. Voir SignalR assemblées dans un framework partagé pour plus d'informations.
Créer et utiliser des hubs
Créez un hub en déclarant une classe qui hérite de Hub et ajoutez-lui des méthodes publiques. Les clients peuvent appeler des méthodes définies comme public
:
public class ChatHub : Hub
{
public Task SendMessage(string user, string message)
{
return Clients.All.SendAsync("ReceiveMessage", user, message);
}
}
Vous pouvez spécifier un type de retour et des paramètres, y compris des types complexes et des tableaux, comme vous le feriez dans n'importe quelle méthode C#. SignalR gère la sérialisation et la désérialisation d'objets complexes et de tableaux dans vos paramètres et valeurs de retour.
Notes
Les hubs sont transitoires :
- Ne stockez pas l'état dans une propriété de la classe hub. Chaque appel de méthode hub est exécuté sur une nouvelle instance hub.
- N'instanciez pas un hub directement via l'injection de dépendances. Pour envoyer des messages à un client depuis un autre endroit de votre application, utilisez un fichier
IHubContext
. - À utiliser
await
lors de l'appel de méthodes asynchrones qui dépendent du maintien en vie du concentrateur. Par exemple, une méthode telle queClients.All.SendAsync(...)
peut échouer si elle est appelée sansawait
et si la méthode hub se termine avantSendAsync
finisse.
L'objet Contexte
La classe Hub a une propriété Context qui contient les propriétés suivantes avec des informations sur la connexion :
Propriété | Description |
---|---|
ConnectionId | Obtient l'ID unique de la connexion, attribué par SignalR. Il existe un ID de connexion pour chaque connexion. |
UserIdentifier | Obtient l'identifiant de l'utilisateur. Par défaut, SignalR utilise le ClaimTypes.NameIdentifier du ClaimsPrincipal associé à la connexion comme identifiant de l'utilisateur. |
User | Obtient le ClaimsPrincipal associé à l'utilisateur actuel. |
Items | Obtient une collection clé/valeur qui peut être utilisée pour partager des données dans le cadre de cette connexion. Les données peuvent être stockées dans cette collection et elles persisteront pour la connexion à travers différentes invocations de méthode de concentrateur. |
Features | Obtient la collection de fonctionnalités disponibles sur la connexion. Obtient la collection de fonctionnalités disponibles sur la connexion. |
ConnectionAborted | Obtient un CancellationToken qui notifie lorsque la connexion est interrompue. |
Hub.Context contient également les méthodes suivantes :
Méthode | Description |
---|---|
GetHttpContext | Renvoie le HttpContext pour la connexion, ou null si la connexion n'est pas associée à une requête HTTP. Pour les connexions HTTP, vous pouvez utiliser cette méthode pour obtenir des informations telles que les en-têtes HTTP et les chaînes de requête. |
Abort | Abandonne la connexion. |
L'objet Clients
La classe Hub a une propriété Clients qui contient les propriétés suivantes pour la communication entre le serveur et le client :
Propriété | Description |
---|---|
All | Appelle une méthode sur tous les clients connectés |
Caller | Appelle une méthode sur le client qui a appelé la méthode hub |
Others | Appelle une méthode sur tous les clients connectés à l'exception du client qui a appelé la méthode |
Hub.Clients contient également les méthodes suivantes :
Méthode | Description |
---|---|
AllExcept | Appelle une méthode sur tous les clients connectés à l'exception des connexions spécifiées |
Client | Appelle une méthode sur un client connecté spécifique |
Clients | Appelle une méthode sur des clients connectés spécifiques |
Group | Appelle une méthode sur toutes les connexions du groupe spécifié |
GroupExcept | Appelle une méthode sur toutes les connexions du groupe spécifié, à l'exception des connexions spécifiées |
Groups | Appelle une méthode sur plusieurs groupes de connexions |
OthersInGroup | Appelle une méthode sur un groupe de connexions, à l'exclusion du client qui a appelé la méthode hub |
User | Appelle une méthode sur toutes les connexions associées à un utilisateur spécifique |
Users | Appelle une méthode sur toutes les connexions associées aux utilisateurs spécifiés |
Chaque propriété ou méthode des tableaux précédents renvoie un objet avec une méthode SendAsync
. La méthode SendAsync
permet de fournir le nom et les paramètres de la méthode cliente à appeler.
Envoyer des messages aux clients
Pour appeler des clients spécifiques, utilisez les propriétés de l'objet Clients
. Dans l'exemple suivant, il existe trois méthodes Hub :
SendMessage
envoie un message à tous les clients connectés, en utilisantClients.All
.SendMessageToCaller
renvoie un message à l'appelant en utilisantClients.Caller
.SendMessageToGroup
envoie un message à tous les clients du groupeSignalR Users
.
public Task SendMessage(string user, string message)
{
return Clients.All.SendAsync("ReceiveMessage", user, message);
}
public Task SendMessageToCaller(string user, string message)
{
return Clients.Caller.SendAsync("ReceiveMessage", user, message);
}
public Task SendMessageToGroup(string user, string message)
{
return Clients.Group("SignalR Users").SendAsync("ReceiveMessage", user, message);
}
Hubs fortement typés
Un inconvénient de l'utilisation SendAsync
est qu'elle s'appuie sur une chaîne magique pour spécifier la méthode client à appeler. Cela laisse le code ouvert aux erreurs d'exécution si le nom de la méthode est mal orthographié ou absent du client.
Une alternative à l'utilisation SendAsync
consiste à taper fortement le Hub avec Hub<T>. Dans l'exemple suivant, les méthodes client ChatHub
ont été extraites dans une interface appelée IChatClient
.
public interface IChatClient
{
Task ReceiveMessage(string user, string message);
}
Cette interface peut être utilisée pour refactoriser l'exemple précédent ChatHub
:
public class StronglyTypedChatHub : Hub<IChatClient>
{
public async Task SendMessage(string user, string message)
{
await Clients.All.ReceiveMessage(user, message);
}
public Task SendMessageToCaller(string user, string message)
{
return Clients.Caller.ReceiveMessage(user, message);
}
}
L'utilisation Hub<IChatClient>
active la vérification au moment de la compilation des méthodes client. Cela évite les problèmes causés par l'utilisation de chaînes magiques, car Hub<T>
ne peuvent donner accès qu'aux méthodes définies dans l'interface.
L'utilisation d'un type fortement Hub<T>
désactivé désactive la possibilité d'utiliser SendAsync
. Toutes les méthodes définies sur l'interface peuvent toujours être définies comme asynchrones. En fait, chacune de ces méthodes devrait renvoyer un fichier Task
. Puisqu'il s'agit d'une interface, n'utilisez pas le mot-clé async
. Par exemple :
public interface IClient
{
Task ClientMethod();
}
Notes
Le suffixe Async
n'est pas supprimé du nom de la méthode. À moins que votre méthode client ne soit définie avec .on('MyMethodAsync')
, vous ne devez pas l'utiliser MyMethodAsync
comme nom.
Changer le nom d'une méthode hub
Par défaut, un nom de méthode de hub de serveur est le nom de la méthode .NET. Cependant, vous pouvez utiliser l'attribut HubMethodName pour modifier cette valeur par défaut et spécifier manuellement un nom pour la méthode. Le client doit utiliser ce nom, au lieu du nom de la méthode .NET, lors de l'appel de la méthode :
[HubMethodName("SendMessageToUser")]
public Task DirectMessage(string user, string message)
{
return Clients.User(user).SendAsync("ReceiveMessage", user, message);
}
Gérer les événements d'une connexion
L'API Hubs SignalR fournit les méthodes virtuelles OnConnectedAsync et OnDisconnectedAsync pour gérer et suivre les connexions. Remplacez la méthode virtuelle OnConnectedAsync
pour effectuer des actions lorsqu'un client se connecte au Hub, comme l'ajouter à un groupe :
public override async Task OnConnectedAsync()
{
await Groups.AddToGroupAsync(Context.ConnectionId, "SignalR Users");
await base.OnConnectedAsync();
}
Remplacez la méthode virtuelle OnDisconnectedAsync
pour effectuer des actions lorsqu'un client se déconnecte. Si le client se déconnecte intentionnellement (en appelant connection.stop()
, par exemple), le paramètre exception
sera null
. Cependant, si le client est déconnecté en raison d'une erreur (telle qu'une panne de réseau), le paramètre exception
contiendra une exception décrivant la panne :
public override async Task OnDisconnectedAsync(Exception exception)
{
await Clients.Group("SignalR Users").SendAsync("ReceiveMessage", "I", "disconnect");
await base.OnDisconnectedAsync(exception);
}
RemoveFromGroupAsync n'a pas besoin d'être appelé OnDisconnectedAsync, il est automatiquement géré pour vous.
Avertissement
Avertissement de sécurité : l'exposition de ConnectionId
peut entraîner une usurpation d'identité malveillante si la version du serveur SignalR ou du client est ASP.NET Core 2.2 ou une version antérieure.
Gérer les erreurs
Les exceptions levées dans vos méthodes de concentrateur sont envoyées au client qui a appelé la méthode. Sur le client JavaScript, la méthode invoke
renvoie un JavaScript Promise
. Lorsque le client reçoit une erreur avec un gestionnaire attaché à la promesse à l'aide de catch
, il est invoqué et transmis en tant qu'objet JavaScript Error
:
connection.invoke("SendMessage", user, message).catch(err => console.error(err));
Si votre hub lève une exception, les connexions ne sont pas fermées. Par défaut, SignalR renvoie un message d'erreur générique au client. Par exemple :
Microsoft.AspNetCore.SignalR.HubException: An unexpected error occurred invoking 'MethodName' on the server.
’Les exceptions inattendues contiennent souvent des informations sensibles, telles que le nom d'un serveur de base de données dans une exception déclenchée lorsque la connexion aux bases de données échoue. SignalR n'expose pas ces messages d'erreur détaillés par défaut par mesure de sécurité. Pour plus d'informations sur la raison pour laquelle les détails de l'exception sont supprimés, consultez Considérations sur la sécurité dans ASP.NET Core SignalR.
Si vous avez une condition exceptionnelle que vous souhaitez propager au client, vous pouvez utiliser la classe HubException. Si vous lancez une méthode HubException
depuis votre concentrateur, SignalRenverra l'intégralité du message au client, sans modification :
public Task ThrowException()
{
throw new HubException("This error will be sent to the client!");
}
Notes
SignalR envoie uniquement la propriété Message
de l'exception au client. La trace de la pile et les autres propriétés de l'exception ne sont pas disponibles pour le client.
Ressources supplémentaires
Par Rachel Appel et Kevin Griffin
Affichez ou téléchargez l’exemple de code (procédure de téléchargement)
Qu'est-ce qu'un hub SignalR
L'API Hubs SignalR permet aux clients connectés d'appeler des méthodes sur le serveur, facilitant ainsi la communication en temps réel. Le serveur définit les méthodes appelées par le client et le client définit les méthodes appelées par le serveur. SignalR permet également une communication client à client indirecte et toujours modérée par le hub SignalR. Cela permet d’envoyer des messages entre des clients individuels, des groupes ou à tous les clients connectés. SignalR prend en charge tout ce qui est nécessaire pour rendre possible la communication client-serveur et serveur-client en temps réel.
Configurer les concentrateurs SignalR
Le middleware SignalR nécessite certains services, qui se configurent en appelant AddSignalR :
services.AddSignalR();
Lors de l'ajout de fonctionnalités SignalR à une application ASP.NET Core, configurez les routes SignalR en appelant UseSignalR dans la méthode Startup.Configure
:
app.UseSignalR(route =>
{
route.MapHub<ChatHub>("/chathub");
});
Créer et utiliser des hubs
Créez un hub en déclarant une classe qui hérite de Hub et ajoutez-lui des méthodes publiques. Les clients peuvent appeler des méthodes définies comme public
:
public class ChatHub : Hub
{
public Task SendMessage(string user, string message)
{
return Clients.All.SendAsync("ReceiveMessage", user, message);
}
}
Vous pouvez spécifier un type de retour et des paramètres, y compris des types complexes et des tableaux, comme vous le feriez dans n'importe quelle méthode C#. SignalR gère la sérialisation et la désérialisation d'objets complexes et de tableaux dans vos paramètres et valeurs de retour.
Notes
Les hubs sont transitoires :
- Ne stockez pas l'état dans une propriété de la classe hub. Chaque appel de méthode hub est exécuté sur une nouvelle instance hub.
- N'instanciez pas un hub directement via l'injection de dépendances. Pour envoyer des messages à un client depuis un autre endroit de votre application, utilisez un fichier
IHubContext
. - À utiliser
await
lors de l'appel de méthodes asynchrones qui dépendent du maintien en vie du concentrateur. Par exemple, une méthode telle queClients.All.SendAsync(...)
peut échouer si elle est appelée sansawait
et si la méthode hub se termine avantSendAsync
finisse.
L'objet Contexte
La classe Hub a une propriété Context qui contient les propriétés suivantes avec des informations sur la connexion :
Propriété | Description |
---|---|
ConnectionId | Obtient l'ID unique de la connexion, attribué par SignalR. Il existe un ID de connexion pour chaque connexion. |
UserIdentifier | Obtient l'identifiant de l'utilisateur. Par défaut, SignalR utilise le ClaimTypes.NameIdentifier du ClaimsPrincipal associé à la connexion comme identifiant de l'utilisateur. |
User | Obtient le ClaimsPrincipal associé à l'utilisateur actuel. |
Items | Obtient une collection clé/valeur qui peut être utilisée pour partager des données dans le cadre de cette connexion. Les données peuvent être stockées dans cette collection et elles persisteront pour la connexion à travers différentes invocations de méthode de concentrateur. |
Features | Obtient la collection de fonctionnalités disponibles sur la connexion. Obtient la collection de fonctionnalités disponibles sur la connexion. |
ConnectionAborted | Obtient un CancellationToken qui notifie lorsque la connexion est interrompue. |
Hub.Context contient également les méthodes suivantes :
Méthode | Description |
---|---|
GetHttpContext | Renvoie le HttpContext pour la connexion, ou null si la connexion n'est pas associée à une requête HTTP. Pour les connexions HTTP, vous pouvez utiliser cette méthode pour obtenir des informations telles que les en-têtes HTTP et les chaînes de requête. |
Abort | Abandonne la connexion. |
L'objet Clients
La classe Hub a une propriété Clients qui contient les propriétés suivantes pour la communication entre le serveur et le client :
Propriété | Description |
---|---|
All | Appelle une méthode sur tous les clients connectés |
Caller | Appelle une méthode sur le client qui a appelé la méthode hub |
Others | Appelle une méthode sur tous les clients connectés à l'exception du client qui a appelé la méthode |
Hub.Clients contient également les méthodes suivantes :
Méthode | Description |
---|---|
AllExcept | Appelle une méthode sur tous les clients connectés à l'exception des connexions spécifiées |
Client | Appelle une méthode sur un client connecté spécifique |
Clients | Appelle une méthode sur des clients connectés spécifiques |
Group | Appelle une méthode sur toutes les connexions du groupe spécifié |
GroupExcept | Appelle une méthode sur toutes les connexions du groupe spécifié, à l'exception des connexions spécifiées |
Groups | Appelle une méthode sur plusieurs groupes de connexions |
OthersInGroup | Appelle une méthode sur un groupe de connexions, à l'exclusion du client qui a appelé la méthode hub |
User | Appelle une méthode sur toutes les connexions associées à un utilisateur spécifique |
Users | Appelle une méthode sur toutes les connexions associées aux utilisateurs spécifiés |
Chaque propriété ou méthode des tableaux précédents renvoie un objet avec une méthode SendAsync
. La méthode SendAsync
permet de fournir le nom et les paramètres de la méthode cliente à appeler.
Envoyer des messages aux clients
Pour appeler des clients spécifiques, utilisez les propriétés de l'objet Clients
. Dans l'exemple suivant, il existe trois méthodes Hub :
SendMessage
envoie un message à tous les clients connectés, en utilisantClients.All
.SendMessageToCaller
renvoie un message à l'appelant en utilisantClients.Caller
.SendMessageToGroup
envoie un message à tous les clients du groupeSignalR Users
.
public Task SendMessage(string user, string message)
{
return Clients.All.SendAsync("ReceiveMessage", user, message);
}
public Task SendMessageToCaller(string user, string message)
{
return Clients.Caller.SendAsync("ReceiveMessage", user, message);
}
public Task SendMessageToGroup(string user, string message)
{
return Clients.Group("SignalR Users").SendAsync("ReceiveMessage", user, message);
}
Hubs fortement typés
Un inconvénient de l'utilisation SendAsync
est qu'elle s'appuie sur une chaîne magique pour spécifier la méthode client à appeler. Cela laisse le code ouvert aux erreurs d'exécution si le nom de la méthode est mal orthographié ou absent du client.
Une alternative à l'utilisation SendAsync
consiste à taper fortement le Hub avec Hub<T>. Dans l'exemple suivant, les méthodes client ChatHub
ont été extraites dans une interface appelée IChatClient
.
public interface IChatClient
{
Task ReceiveMessage(string user, string message);
}
Cette interface peut être utilisée pour refactoriser l'exemple précédent ChatHub
:
public class StronglyTypedChatHub : Hub<IChatClient>
{
public async Task SendMessage(string user, string message)
{
await Clients.All.ReceiveMessage(user, message);
}
public Task SendMessageToCaller(string user, string message)
{
return Clients.Caller.ReceiveMessage(user, message);
}
}
L'utilisation Hub<IChatClient>
active la vérification au moment de la compilation des méthodes client. Cela évite les problèmes causés par l'utilisation de chaînes magiques, car Hub<T>
ne peuvent donner accès qu'aux méthodes définies dans l'interface.
L'utilisation d'un type fortement Hub<T>
désactivé désactive la possibilité d'utiliser SendAsync
. Toutes les méthodes définies sur l'interface peuvent toujours être définies comme asynchrones. En fait, chacune de ces méthodes devrait renvoyer un fichier Task
. Puisqu'il s'agit d'une interface, n'utilisez pas le mot-clé async
. Par exemple :
public interface IClient
{
Task ClientMethod();
}
Notes
Le suffixe Async
n'est pas supprimé du nom de la méthode. À moins que votre méthode client ne soit définie avec .on('MyMethodAsync')
, vous ne devez pas l'utiliser MyMethodAsync
comme nom.
Changer le nom d'une méthode hub
Par défaut, un nom de méthode de hub de serveur est le nom de la méthode .NET. Cependant, vous pouvez utiliser l'attribut HubMethodName pour modifier cette valeur par défaut et spécifier manuellement un nom pour la méthode. Le client doit utiliser ce nom, au lieu du nom de la méthode .NET, lors de l'appel de la méthode :
[HubMethodName("SendMessageToUser")]
public Task DirectMessage(string user, string message)
{
return Clients.User(user).SendAsync("ReceiveMessage", user, message);
}
Gérer les événements d'une connexion
L'API Hubs SignalR fournit les méthodes virtuelles OnConnectedAsync et OnDisconnectedAsync pour gérer et suivre les connexions. Remplacez la méthode virtuelle OnConnectedAsync
pour effectuer des actions lorsqu'un client se connecte au Hub, comme l'ajouter à un groupe :
public override async Task OnConnectedAsync()
{
await Groups.AddToGroupAsync(Context.ConnectionId, "SignalR Users");
await base.OnConnectedAsync();
}
Remplacez la méthode virtuelle OnDisconnectedAsync
pour effectuer des actions lorsqu'un client se déconnecte. Si le client se déconnecte intentionnellement (en appelant connection.stop()
, par exemple), le paramètre exception
sera null
. Cependant, si le client est déconnecté en raison d'une erreur (telle qu'une panne de réseau), le paramètre exception
contiendra une exception décrivant la panne :
public override async Task OnDisconnectedAsync(Exception exception)
{
await Clients.Group("SignalR Users").SendAsync("ReceiveMessage", "I", "disconnect");
await base.OnDisconnectedAsync(exception);
}
RemoveFromGroupAsync n'a pas besoin d'être appelé OnDisconnectedAsync, il est automatiquement géré pour vous.
Avertissement
Avertissement de sécurité : l'exposition de ConnectionId
peut entraîner une usurpation d'identité malveillante si la version du serveur SignalR ou du client est ASP.NET Core 2.2 ou une version antérieure.
Gérer les erreurs
Les exceptions levées dans vos méthodes de concentrateur sont envoyées au client qui a appelé la méthode. Sur le client JavaScript, la méthode invoke
renvoie un JavaScript Promise
. Lorsque le client reçoit une erreur avec un gestionnaire attaché à la promesse à l'aide de catch
, il est invoqué et transmis en tant qu'objet JavaScript Error
:
connection.invoke("SendMessage", user, message).catch(err => console.error(err));
Si votre hub lève une exception, les connexions ne sont pas fermées. Par défaut, SignalR renvoie un message d'erreur générique au client. Par exemple :
Microsoft.AspNetCore.SignalR.HubException: An unexpected error occurred invoking 'MethodName' on the server.
’Les exceptions inattendues contiennent souvent des informations sensibles, telles que le nom d'un serveur de base de données dans une exception déclenchée lorsque la connexion aux bases de données échoue. SignalR n'expose pas ces messages d'erreur détaillés par défaut par mesure de sécurité. Pour plus d'informations sur la raison pour laquelle les détails de l'exception sont supprimés, consultez Considérations sur la sécurité dans ASP.NET Core SignalR.
Si vous avez une condition exceptionnelle que vous souhaitez propager au client, vous pouvez utiliser la classe HubException. Si vous lancez une méthode HubException
depuis votre concentrateur, SignalRenverra l'intégralité du message au client, sans modification :
public Task ThrowException()
{
throw new HubException("This error will be sent to the client!");
}
Notes
SignalR envoie uniquement la propriété Message
de l'exception au client. La trace de la pile et les autres propriétés de l'exception ne sont pas disponibles pour le client.