Udostępnij za pośrednictwem


Używanie filtrów koncentratora w programie ASP.NET Core SignalR

Filtry koncentratora:

  • Są dostępne w wersji ASP.NET Core 5.0 lub nowszej.
  • Zezwól na uruchamianie logiki przed i po wywołaniu metod centrum przez klientów.

Ten artykuł zawiera wskazówki dotyczące pisania i używania filtrów centrum.

Konfigurowanie filtrów koncentratora

Filtry koncentratora można stosować globalnie lub na typ koncentratora. Kolejność dodawania filtrów to kolejność uruchamiania filtrów. Filtry koncentratora globalnego są uruchamiane przed filtrami koncentratora lokalnego.

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

Filtr koncentratora można dodać w jeden z następujących sposobów:

  • Dodaj filtr według konkretnego typu:

    hubOptions.AddFilter<TFilter>();
    

    Zostanie to rozwiązane z iniekcji zależności (DI) lub aktywowanego typu.

  • Dodaj filtr według typu środowiska uruchomieniowego:

    hubOptions.AddFilter(typeof(TFilter));
    

    Zostanie to rozwiązane z di lub typu aktywowane.

  • Dodaj filtr według wystąpienia:

    hubOptions.AddFilter(new MyFilter());
    

    To wystąpienie będzie używane jak pojedyncze wystąpienie. Wszystkie wywołania metody koncentratora będą używać tego samego wystąpienia.

Filtry koncentratora są tworzone i usuwane dla wywołania koncentratora. Jeśli chcesz przechowywać stan globalny w filtrze lub bez stanu, dodaj typ filtru koncentratora do nazwy DI jako jedenton, aby uzyskać lepszą wydajność. Alternatywnie dodaj filtr jako wystąpienie, jeśli to możliwe.

Tworzenie filtrów koncentratora

Utwórz filtr, deklarując klasę dziedziczącą z IHubFilterklasy i dodając metodę InvokeMethodAsync . Istnieje również OnConnectedAsync i OnDisconnectedAsync można to opcjonalnie zaimplementować, aby opakowować OnConnectedAsync odpowiednio metody i OnDisconnectedAsync koncentratora.

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

Filtry są bardzo podobne do oprogramowania pośredniczącego. Metoda next wywołuje następny filtr. Końcowy filtr wywoła metodę centrum. Filtry mogą również przechowywać wynik z oczekiwania next i uruchomienia logiki po wywołaniu metody centrum przed zwróceniem wyniku z nextklasy .

Aby pominąć wywołanie metody centrum w filtrze, należy zgłosić wyjątek typu HubException zamiast wywoływać metodę next. Klient otrzyma błąd, jeśli spodziewał się wyniku.

Korzystanie z filtrów koncentratora

Podczas pisania logiki filtru spróbuj wprowadzić ją ogólną przy użyciu atrybutów w metodach centrum zamiast sprawdzania nazw metod centrum.

Rozważ filtr, który sprawdzi argument metody centrum dla zakazanych fraz i zastąpi wszystkie znalezione frazy ciągiem ***. W tym przykładzie przyjęto założenie, że klasa jest zdefiniowana LanguageFilterAttribute . Klasa ma właściwość o nazwie FilterArgument , którą można ustawić podczas używania atrybutu.

  1. Umieść atrybut w metodzie centrum, która ma argument ciągu do wyczyszczenia:

    public class ChatHub
    {
        [LanguageFilter(filterArgument = 0)]
        public async Task SendMessage(string message, string username)
        {
            await Clients.All.SendAsync("SendMessage", $"{username} says: {message}");
        }
    }
    
  2. Zdefiniuj filtr koncentratora w celu sprawdzenia atrybutu i zastąp niedozwolone frazy w argumencie metody centrum wartością ***:

    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. Zarejestruj filtr koncentratora w metodzie Startup.ConfigureServices . Aby uniknąć ponownego inicjowania listy zakazanych fraz dla każdego wywołania, filtr centrum jest rejestrowany jako pojedynczy:

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

Obiekt HubInvocationContext

Zawiera HubInvocationContext informacje dotyczące wywołania bieżącej metody centrum.

Właściwości Opis Type
Context Zawiera HubCallerContext informacje o połączeniu. HubCallerContext
Hub Wystąpienie centrum używane do wywołania tej metody centrum. Hub
HubMethodName Nazwa wywoływanej metody centrum. string
HubMethodArguments Lista argumentów przekazywanych do metody centrum. IReadOnlyList<string>
ServiceProvider Dostawca usług o określonym zakresie dla wywołania tej metody centrum. IServiceProvider
HubMethod Informacje o metodzie centrum. MethodInfo

Obiekt HubLifetimeContext

Zawiera HubLifetimeContext informacje dotyczące OnConnectedAsync metod i OnDisconnectedAsync centrum.

Właściwości Opis Type
Context Zawiera HubCallerContext informacje o połączeniu. HubCallerContext
Hub Wystąpienie centrum używane do wywołania tej metody centrum. Hub
ServiceProvider Dostawca usług o określonym zakresie dla wywołania tej metody centrum. IServiceProvider

Autoryzacja i filtry

Autoryzowanie atrybutów w metodach centrum jest uruchamiane przed filtrami koncentratora.