Bagikan melalui


Gunakan filter hub pada ASP.NET Core SignalR

Filter hub:

  • Tersedia di .NET 5 atau yang lebih baru.
  • Izinkan logika berjalan sebelum dan sesudah metode hub dipanggil oleh klien.

Artikel ini menyediakan panduan untuk menulis dan menggunakan filter hub.

Mengatur filter hub

Filter hub dapat diterapkan secara global atau per jenis hub. Urutan penambahan filter adalah urutan di mana filter tersebut dijalankan. Filter hub global berjalan sebelum filter hub lokal.

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

Filter hub dapat ditambahkan dengan salah satu cara berikut:

  • Tambahkan filter menurut jenis beton:

    hubOptions.AddFilter<TFilter>();
    

    Ini akan diselesaikan dari injeksi dependensi (DI) atau diaktifkan berdasarkan tipe.

  • Tambahkan filter menurut jenis runtime:

    hubOptions.AddFilter(typeof(TFilter));
    

    Ini akan diselesaikan dari DI atau jenis yang diaktifkan.

  • Tambahkan filter menurut instans:

    hubOptions.AddFilter(new MyFilter());
    

    Instansi ini akan digunakan seperti singleton. Semua pemanggilan metode hub akan menggunakan instans yang sama.

Filter pada hub dibuat dan dibuang setiap kali pemanggilan hub dilakukan. Jika Anda ingin menyimpan status global dalam filter, atau tanpa status apa pun, tambahkan tipe filter hub ke DI sebagai "singleton" untuk performa yang lebih baik. Atau, tambahkan filter sebagai instance jika Anda bisa.

Membuat filter hub

Buat filter dengan mendeklarasikan kelas yang mewarisi dari IHubFilter, dan tambahkan InvokeMethodAsync metode . Ada juga OnConnectedAsync dan OnDisconnectedAsync yang dapat secara opsional diimplementasikan untuk membungkus OnConnectedAsync metode hub dan OnDisconnectedAsync masing-masing.

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

Filter sangat mirip dengan middleware. Metode next memanggil filter berikutnya. Filter akhir akan memanggil metode hub. Filter juga dapat menyimpan hasil dari menunggu next dan menjalankan logika setelah metode hub dipanggil sebelum mengembalikan hasil dari next.

Untuk melewati pemanggilan metode hub dalam filter, berikan pengecualian jenis HubException alih-alih memanggil next. Klien akan menerima kesalahan jika mengharapkan hasilnya.

Menggunakan filter hub

Saat menulis logika filter, coba buat generik dengan menggunakan atribut pada metode hub alih-alih memeriksa nama metode hub.

Pertimbangkan filter yang akan memeriksa argumen metode hub untuk frasa yang dilarang dan mengganti frasa apa pun yang ditemukannya dengan ***. Untuk contoh ini, asumsikan kelas LanguageFilterAttribute telah ditentukan. Kelas memiliki properti bernama FilterArgument yang dapat diatur saat menggunakan atribut .

  1. Tempatkan atribut pada metode hub yang memiliki argumen string yang akan dibersihkan:

    public class ChatHub
    {
        [LanguageFilter(filterArgument = 0)]
        public async Task SendMessage(string message, string username)
        {
            await Clients.All.SendAsync("SendMessage", $"{username} says: {message}");
        }
    }
    
  2. Tentukan filter hub untuk memeriksa atribut dan mengganti frasa yang dilarang dalam argumen metode hub dengan ***:

    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. Daftarkan filter hub pada metode Startup.ConfigureServices. Untuk menghindari menginisialisasi ulang daftar frasa yang dilarang untuk setiap pemanggilan, filter hub terdaftar sebagai singleton:

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

Objek HubInvocationContext

HubInvocationContext berisi informasi untuk pemanggilan metode hub saat ini.

Harta benda Deskripsi Tipe
Context HubCallerContext berisi informasi tentang koneksi. HubCallerContext
Hub Instans Hub yang digunakan untuk pemanggilan metode hub ini. Hub
HubMethodName Nama metode hub yang sedang dipanggil. string
HubMethodArguments Daftar argumen yang diteruskan ke metode hub. IReadOnlyList<string>
ServiceProvider Penyedia layanan terlingkup untuk pemanggilan metode hub ini. IServiceProvider
HubMethod Informasi metode pusat. MethodInfo

Objek HubLifetimeContext

HubLifetimeContext berisi informasi untuk metode-metode hub OnConnectedAsync dan OnDisconnectedAsync.

Harta benda Deskripsi Tipe
Context HubCallerContext berisi informasi tentang koneksi. HubCallerContext
Hub Instans Hub yang digunakan untuk pemanggilan metode hub ini. Hub
ServiceProvider Penyedia layanan terlingkup untuk pemanggilan metode hub ini. IServiceProvider

Otorisasi dan filter

Otorisasi atribut pada metode hub yang dijalankan sebelum filter hub.