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. Le serveur définit les méthodes qui sont appelées depuis le client et le client définit les méthodes qui sont appelées depuis le serveur. 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 que Clients.All.SendAsync(...) peut échouer si elle est appelée sans await et si la méthode hub se termine avant SendAsync 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 utilisant Clients.All.
  • SendMessageToCaller renvoie un message à l'appelant en utilisant Clients.Caller.
  • SendMessageToGroup envoie un message à tous les clients du groupe SignalR 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. Le serveur définit les méthodes qui sont appelées depuis le client et le client définit les méthodes qui sont appelées depuis le serveur. 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 que Clients.All.SendAsync(...) peut échouer si elle est appelée sans await et si la méthode hub se termine avant SendAsync 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 utilisant Clients.All.
  • SendMessageToCaller renvoie un message à l'appelant en utilisant Clients.Caller.
  • SendMessageToGroup envoie un message à tous les clients du groupe SignalR 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. Le serveur définit les méthodes qui sont appelées depuis le client et le client définit les méthodes qui sont appelées depuis le serveur. 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 que Clients.All.SendAsync(...) peut échouer si elle est appelée sans await et si la méthode hub se termine avant SendAsync 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 utilisant Clients.All.
  • SendMessageToCaller renvoie un message à l'appelant en utilisant Clients.Caller.
  • SendMessageToGroup envoie un message à tous les clients du groupe SignalR 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

Afficher ou télécharger l’exemple de code(procédure de téléchargement)

Qu'est-ce qu'un hub SignalR

L'API Hubs SignalR vous permet d'appeler des méthodes sur des clients connectés à partir du serveur. Dans le code du serveur, vous définissez les méthodes qui sont appelées par le client. Dans le code client, vous définissez les méthodes qui sont appelées depuis le serveur. SignalR s'occupe de tout ce qui, en coulisse, rend possible les communications 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 que Clients.All.SendAsync(...) peut échouer si elle est appelée sans await et si la méthode hub se termine avant SendAsync 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 utilisant Clients.All.
  • SendMessageToCaller renvoie un message à l'appelant en utilisant Clients.Caller.
  • SendMessageToGroup envoie un message à tous les clients du groupe SignalR 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

Afficher ou télécharger l’exemple de code(procédure de téléchargement)

Qu'est-ce qu'un hub SignalR

L'API Hubs SignalR vous permet d'appeler des méthodes sur des clients connectés à partir du serveur. Dans le code du serveur, vous définissez les méthodes qui sont appelées par le client. Dans le code client, vous définissez les méthodes qui sont appelées depuis le serveur. SignalR s'occupe de tout ce qui, en coulisse, rend possible les communications 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 que Clients.All.SendAsync(...) peut échouer si elle est appelée sans await et si la méthode hub se termine avant SendAsync 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 utilisant Clients.All.
  • SendMessageToCaller renvoie un message à l'appelant en utilisant Clients.Caller.
  • SendMessageToGroup envoie un message à tous les clients du groupe SignalR 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