Condividi tramite


Usare i filtri hub in ASP.NET Core SignalR

Filtri hub:

  • Sono disponibili in ASP.NET Core 5.0 o versione successiva.
  • Consentire l'esecuzione della logica prima e dopo i metodi hub vengono richiamati dai client.

Questo articolo fornisce indicazioni per la scrittura e l'uso di filtri hub.

Configurare i filtri hub

I filtri hub possono essere applicati a livello globale o per tipo di hub. L'ordine in cui vengono aggiunti i filtri è l'ordine in cui vengono eseguiti i filtri. I filtri dell'hub globale vengono eseguiti prima dei filtri dell'hub locale.

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

È possibile aggiungere un filtro hub in uno dei modi seguenti:

  • Aggiungere un filtro per tipo concreto:

    hubOptions.AddFilter<TFilter>();
    

    Questo problema verrà risolto dall'inserimento delle dipendenze (DI) o dal tipo attivato.

  • Aggiungere un filtro in base al tipo di runtime:

    hubOptions.AddFilter(typeof(TFilter));
    

    Il problema verrà risolto da DI o dal tipo attivato.

  • Aggiungere un filtro per istanza:

    hubOptions.AddFilter(new MyFilter());
    

    Questa istanza verrà usata come un singleton. Tutte le chiamate al metodo hub useranno la stessa istanza.

I filtri hub vengono creati ed eliminati per ogni chiamata all'hub. Se si vuole archiviare lo stato globale nel filtro o nessuno stato, aggiungere il tipo di filtro hub a DI come singleton per ottenere prestazioni migliori. In alternativa, aggiungere il filtro come istanza, se possibile.

Creare filtri hub

Creare un filtro dichiarando una classe che eredita da IHubFiltere aggiungere il InvokeMethodAsync metodo . È anche OnConnectedAsync possibile implementare e OnDisconnectedAsync , facoltativamente, per eseguire il wrapping dei OnConnectedAsync metodi hub e OnDisconnectedAsync rispettivamente.

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

I filtri sono molto simili al middleware. Il next metodo richiama il filtro successivo. Il filtro finale richiamerà il metodo hub. I filtri possono anche archiviare il risultato dall'attesa next ed eseguire la logica dopo che il metodo hub è stato chiamato prima di restituire il risultato da next.

Per ignorare una chiamata al metodo hub in un filtro, generare un'eccezione di tipo HubException anziché chiamare next. Il client riceverà un errore se si aspettava un risultato.

Usare i filtri hub

Quando si scrive la logica del filtro, provare a renderla generica usando attributi sui metodi hub anziché cercare i nomi dei metodi hub.

Si consideri un filtro che verificherà un argomento del metodo hub per le frasi escluse e sostituirà tutte le frasi trovate con ***. Per questo esempio, si supponga che sia definita una LanguageFilterAttribute classe . La classe ha una proprietà denominata che può essere impostata FilterArgument quando si usa l'attributo .

  1. Posizionare l'attributo nel metodo hub con un argomento stringa da pulire:

    public class ChatHub
    {
        [LanguageFilter(filterArgument = 0)]
        public async Task SendMessage(string message, string username)
        {
            await Clients.All.SendAsync("SendMessage", $"{username} says: {message}");
        }
    }
    
  2. Definire un filtro hub per verificare la presenza dell'attributo e sostituire frasi escluse in un argomento del metodo hub con ***:

    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. Registrare il filtro hub nel Startup.ConfigureServices metodo . Per evitare di reinizializzare l'elenco di frasi escluse per ogni chiamata, il filtro hub viene registrato come singleton:

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

Oggetto HubInvocationContext

HubInvocationContext Contiene informazioni per la chiamata al metodo hub corrente.

Proprietà Descrizione Digita
Context HubCallerContext Contiene informazioni sulla connessione. HubCallerContext
Hub Istanza dell'hub usata per la chiamata al metodo hub. Hub
HubMethodName Nome del metodo hub richiamato. string
HubMethodArguments Elenco di argomenti passati al metodo hub. IReadOnlyList<string>
ServiceProvider Provider di servizi con ambito per questa chiamata al metodo hub. IServiceProvider
HubMethod Informazioni sul metodo hub. MethodInfo

Oggetto HubLifetimeContext

HubLifetimeContext Contiene informazioni per i metodi dell'hub OnConnectedAsync e OnDisconnectedAsync .

Proprietà Descrizione Digita
Context HubCallerContext Contiene informazioni sulla connessione. HubCallerContext
Hub Istanza dell'hub usata per la chiamata al metodo hub. Hub
ServiceProvider Provider di servizi con ambito per questa chiamata al metodo hub. IServiceProvider

Autorizzazione e filtri

Autorizzare gli attributi nei metodi hub eseguiti prima dei filtri dell'hub.