Partager via


Utiliser des filtres hub dans ASP.NET Core SignalR

Filtres hub :

  • Sont disponibles dans .NET 5 ou version ultérieure.
  • Autoriser l’exécution de la logique avant et après l’appel des méthodes hub par les clients.

Cet article fournit des conseils pour l’écriture et l’utilisation de filtres hub.

Configurer des filtres hub

Les filtres hub peuvent être appliqués globalement ou par type de hub. L’ordre dans lequel les filtres sont ajoutés est l’ordre dans lequel les filtres s’exécutent. Les filtres de hub global s’exécutent avant les filtres de hub local.

public void ConfigureServices(IServiceCollection services)
{
    services.AddSignalR(options =>
    {
        // Global filters will run first
        options.AddFilter<CustomFilter>();
    }).AddHubOptions<ChatHub>(options =>
    {
        // Local filters will run second
        options.AddFilter<CustomFilter2>();
    });
}

Un filtre hub peut être ajouté de l’une des manières suivantes :

  • Ajoutez un filtre par type concret :

    hubOptions.AddFilter<TFilter>();
    

    Cela sera résolu à partir de l’injection de dépendances (DI) ou par activation de type.

  • Ajoutez un filtre par type d’exécution :

    hubOptions.AddFilter(typeof(TFilter));
    

    Cela sera résolu à partir de DI ou du type activé.

  • Ajoutez un filtre par instance :

    hubOptions.AddFilter(new MyFilter());
    

    Cette instance sera utilisée comme un singleton. Tous les appels de méthode hub utilisent la même instance.

Les filtres hub sont créés et supprimés par appel de hub. Si vous souhaitez stocker l’état global dans le filtre, ou pas d’état, ajoutez le type de filtre hub à DI en tant que singleton pour de meilleures performances. Vous pouvez également ajouter le filtre en tant qu’instance si vous le pouvez.

Créer des filtres hub

Créez un filtre en déclarant une classe qui hérite de IHubFilter, puis ajoutez la InvokeMethodAsync méthode. Il existe également OnConnectedAsync et OnDisconnectedAsync qui peuvent être implémentés pour encapsuler respectivement les méthodes OnConnectedAsync et OnDisconnectedAsync du hub.

public class CustomFilter : IHubFilter
{
    public async ValueTask<object> InvokeMethodAsync(
        HubInvocationContext invocationContext, Func<HubInvocationContext, ValueTask<object>> next)
    {
        Console.WriteLine($"Calling hub method '{invocationContext.HubMethodName}'");
        try
        {
            return await next(invocationContext);
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Exception calling '{invocationContext.HubMethodName}': {ex}");
            throw;
        }
    }

    // Optional method
    public Task OnConnectedAsync(HubLifetimeContext context, Func<HubLifetimeContext, Task> next)
    {
        return next(context);
    }

    // Optional method
    public Task OnDisconnectedAsync(
        HubLifetimeContext context, Exception exception, Func<HubLifetimeContext, Exception, Task> next)
    {
        return next(context, exception);
    }
}

Les filtres sont très similaires aux intergiciels. La next méthode appelle le filtre suivant. Le filtre final appelle la méthode hub. Les filtres peuvent également stocker le résultat de l'attente de next et exécuter la logique après l'appel de la méthode du hub, avant de renvoyer le résultat de next.

Pour ignorer un appel de méthode hub dans un filtre, lèvez une exception de type HubException au lieu d’appeler next. Le client reçoit une erreur s’il attendait un résultat.

Utiliser des filtres hub

Lors de l’écriture de la logique de filtre, essayez de la rendre générique en utilisant des attributs sur les méthodes du concentrateur au lieu de vérifier les noms de méthodes du concentrateur.

Imaginez un filtre qui vérifie un argument d'une méthode de hub afin de détecter des expressions interdites et remplace toute expression qu'il trouve par ***. Pour cet exemple, supposons qu’une LanguageFilterAttribute classe est définie. La classe a une propriété nommée FilterArgument qui peut être définie lors de l’utilisation de l’attribut.

  1. Placez l’attribut sur la méthode hub qui a un argument de chaîne à nettoyer :

    public class ChatHub
    {
        [LanguageFilter(filterArgument = 0)]
        public async Task SendMessage(string message, string username)
        {
            await Clients.All.SendAsync("SendMessage", $"{username} says: {message}");
        }
    }
    
  2. Définissez un filtre hub pour rechercher l’attribut et remplacer les expressions interdites dans un argument de méthode hub par ***:

    public class LanguageFilter : IHubFilter
    {
        // populated from a file or inline
        private List<string> bannedPhrases = new List<string> { "async void", ".Result" };
    
        public async ValueTask<object> InvokeMethodAsync(HubInvocationContext invocationContext, 
            Func<HubInvocationContext, ValueTask<object>> next)
        {
            var languageFilter = (LanguageFilterAttribute)Attribute.GetCustomAttribute(
                invocationContext.HubMethod, typeof(LanguageFilterAttribute));
            if (languageFilter != null &&
                invocationContext.HubMethodArguments.Count > languageFilter.FilterArgument &&
                invocationContext.HubMethodArguments[languageFilter.FilterArgument] is string str)
            {
                foreach (var bannedPhrase in bannedPhrases)
                {
                    str = str.Replace(bannedPhrase, "***");
                }
    
                var arguments = invocationContext.HubMethodArguments.ToArray();
                arguments[languageFilter.FilterArgument] = str;
                invocationContext = new HubInvocationContext(invocationContext.Context,
                    invocationContext.ServiceProvider,
                    invocationContext.Hub,
                    invocationContext.HubMethod,
                    arguments);
            }
    
            return await next(invocationContext);
        }
    }
    
  3. Inscrivez le filtre hub dans la Startup.ConfigureServices méthode. Pour éviter de réinitialiser la liste des expressions interdites pour chaque appel, le filtre hub est inscrit en tant que singleton :

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddSignalR(hubOptions =>
        {
            hubOptions.AddFilter<LanguageFilter>();
        });
    
        services.AddSingleton<LanguageFilter>();
    }
    

Objet HubInvocationContext

HubInvocationContext contient des informations pour l’appel de méthode hub actuel.

Propriété Descriptif Catégorie
Context Le HubCallerContext contient des informations sur la connexion. HubCallerContext
Hub Instance du hub utilisée pour cet appel de méthode hub. Hub
HubMethodName Nom de la méthode du hub en cours d'invocation. string
HubMethodArguments Liste des arguments passés à la méthode hub. IReadOnlyList<string>
ServiceProvider Fournisseur de services délimité pour cet appel de méthode hub. IServiceProvider
HubMethod Informations sur la méthode hub. MethodInfo

Objet HubLifetimeContext

Le HubLifetimeContext contient des informations pour les méthodes de hub OnConnectedAsync et OnDisconnectedAsync.

Propriété Descriptif Catégorie
Context Le HubCallerContext contient des informations sur la connexion. HubCallerContext
Hub Instance du hub utilisée pour cet appel de méthode hub. Hub
ServiceProvider Fournisseur de services délimité pour cet appel de méthode hub. IServiceProvider

Autorisation et filtres

Les attributs d'autorisation sur les méthodes de hub s'exécutent avant les filtres de hub.