Menggunakan hub di ASP.NET Core SignalR

Oleh Rachel Appel dan Kevin Griffin

SignalR HUBS API memungkinkan klien yang terhubung untuk memanggil metode di server, memfasilitasi komunikasi real-time. Server mendefinisikan metode yang dipanggil oleh klien, dan klien menentukan metode yang dipanggil oleh server. SignalR juga memungkinkan komunikasi tidak langsung antar-klien, dengan SignalR Hub bertindak sebagai perantara. Pendekatan ini memungkinkan pengiriman pesan antara klien individu, grup, atau ke semua klien yang terhubung. SignalR mengurus semua yang diperlukan untuk memungkinkan komunikasi klien-ke-server dan server-ke-klien secara real-time.

Artikel ini menjelaskan cara mengonfigurasi hub, mengirim pesan ke klien, dan memungkinkan server menangani hasil dari klien.

Mengonfigurasi SignalR hub

Daftarkan layanan yang diperlukan oleh SignalR hub dengan memanggil AddSignalR metode dalam file Program.cs :

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddSignalR();

Konfigurasikan SignalR endpoint dengan memanggil metode MapHub di file Program.cs:

app.MapRazorPages();
app.MapHub<ChatHub>("/Chat");

app.Run();

Note

ASP.NET Core SignalR komponen sisi server sekarang diinstal dengan .NET Core SDK. Untuk informasi selengkapnya, lihat SignalR rakitan dalam kerangka kerja bersama.

Membuat dan menggunakan hub

Buat hub dengan mendeklarasikan kelas yang mewarisi dari Hub. Tambahkan public metode ke kelas untuk membuatnya dapat dipanggil dari klien:

public class ChatHub : Hub
{
    public async Task SendMessage(string user, string message)
        => await Clients.All.SendAsync("ReceiveMessage", user, message);
}

Note

Hub bersifat sementara:

  • Jangan menyimpan status di properti kelas hub. Setiap panggilan metode hub dijalankan pada instans hub baru.
  • Jangan membuat instans hub secara langsung melalui injeksi dependensi. Untuk mengirim pesan ke klien dari tempat lain di aplikasi Anda, gunakan IHubContext.
  • Gunakan await saat memanggil metode asinkron yang bergantung pada hub tetap hidup. Misalnya, jika Anda memanggil metode seperti Clients.All.SendAsync(...) tanpa menggunakan await, panggilan dapat gagal dan metode hub selesai sebelum SendAsync selesai.

Note

Parameter metode hub, nilai pengembalian, dan item streaming hanya dapat berupa jenis serikat C# dengan default JsonHubProtocol. Protokol hub MessagePack dan Newtonsoft.Json tidak mendukung union.

Menggunakan properti dan metode objek 'Konteks'

Kelas Hub menyertakan Context properti yang berisi properti berikut dengan informasi tentang koneksi:

Property Description
ConnectionId Mendapatkan ID unik untuk koneksi, yang ditetapkan oleh SignalR. Ada satu ID koneksi untuk setiap koneksi.
UserIdentifier Mendapatkan pengidentifikasi pengguna. Secara bawaan, SignalR menggunakan properti ClaimTypes.NameIdentifier dari ClaimsPrincipal yang terkait dengan koneksi sebagai pengidentifikasi pengguna.
User Mendapatkan ClaimsPrincipal yang terkait dengan pengguna saat ini.
Items Mendapatkan kumpulan kunci/nilai yang dapat digunakan untuk berbagi data dalam cakupan koneksi ini. Data dapat disimpan dalam koleksi ini dan tetap ada untuk koneksi di berbagai pemanggilan metode hub.
Features Mendapatkan kumpulan fitur yang tersedia pada koneksi. Koleksi ini saat ini tidak diperlukan dalam sebagian besar skenario, sehingga dokumentasi terperinci belum tersedia.
ConnectionAborted Mendapatkan sebuah CancellationToken yang memberi tahu ketika koneksi dibatalkan.

Properti Hub.Context juga berisi metode berikut:

Method Description
GetHttpContext Mengembalikan HttpContext untuk koneksi, atau null jika koneksi tidak terkait dengan permintaan HTTP. Untuk koneksi HTTP, gunakan metode ini untuk mendapatkan informasi seperti header HTTP dan string kueri.
Abort Membatalkan koneksi.

Menggunakan properti dan metode objek 'Klien'

Kelas Hub menyertakan Clients properti yang berisi properti berikut untuk komunikasi antara server dan klien:

Property Description
All Memanggil metode pada semua klien yang terhubung.
Caller Memanggil metode pada klien yang memanggil metode hub.
Others Memanggil metode pada semua klien yang terhubung kecuali klien yang memanggil metode .

Properti Hub.Clients juga berisi metode berikut:

Method Description
AllExcept Memanggil metode pada semua klien yang terhubung kecuali pada koneksi yang ditentukan.
Client Memanggil metode pada klien tertentu yang terhubung.
Clients Memanggil metode pada klien tertentu yang terhubung.
Group Memanggil metode pada semua koneksi dalam grup yang ditentukan.
GroupExcept Memanggil metode pada semua koneksi dalam grup yang ditentukan, kecuali koneksi yang ditentukan.
Groups Memanggil metode pada beberapa grup koneksi.
OthersInGroup Memanggil metode pada sekelompok koneksi, tidak termasuk klien yang memanggil metode hub.
User Memanggil metode pada semua koneksi yang terkait dengan pengguna tertentu.
Users Memanggil metode pada semua koneksi yang terkait dengan pengguna yang ditentukan.

Setiap properti atau metode mengembalikan objek dengan metode SendAsync. Metode SendAsync menerima nama metode klien yang akan dipanggil serta parameter apa pun.

Objek yang dikembalikan oleh metode Client dan Caller juga berisi metode InvokeAsync, yang dapat digunakan untuk menunggu hasil dari klien.

Mengirim pesan ke klien

Untuk melakukan panggilan ke klien tertentu, gunakan properti Clients objek. Dalam contoh berikut, ada tiga metode hub:

  • Metode SendMessage mengirim pesan ke semua klien yang terhubung dengan menggunakan properti Clients.All.
  • Metode SendMessageToCaller mengirim pesan kembali ke pemanggil dengan menggunakan Clients.Caller properti .
  • Metode mengirim SendMessageToGroup pesan ke semua klien dalam SignalR Users grup.
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);

Gunakan hub bertipe kuat

Kelemahan menggunakan SendAsync metode ini adalah mengandalkan string untuk menentukan metode klien yang akan dipanggil. Desain ini membuat kode terbuka untuk kesalahan runtime jika nama metode salah eja atau hilang dari klien.

Alternatif selain menggunakan metode SendAsync adalah dengan menetapkan tipe yang kuat pada kelas Hub dengan Hub<T>. Dalam contoh berikut, ChatHub metode klien diekstrak ke antarmuka bernama IChatClient:

public interface IChatClient
{
    Task ReceiveMessage(string user, string message);
}

Antarmuka ini dapat digunakan untuk merefaktor contoh sebelumnya ChatHub agar menjadi bertipe kuat:

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

Menggunakan Hub<IChatClient> mengaktifkan pemeriksaan waktu kompilasi metode klien. Pendekatan ini mencegah masalah yang disebabkan oleh penggunaan string karena Hub<T> hanya dapat menyediakan akses ke metode yang ditentukan dalam antarmuka. Menggunakan Hub<T> tipe kuat menonaktifkan kemampuan menggunakan metode SendAsync.

Note

Akhiran Async tidak dihapus dari nama metode. Kecuali metode klien didefinisikan dengan .on('MyMethodAsync'), jangan gunakan MyMethodAsync sebagai nama.

Meminta hasil klien

Selain melakukan panggilan ke klien, server dapat meminta hasil dari klien. Dalam skenario ini, server menggunakan ISingleClientProxy.InvokeAsync metode dan klien mengembalikan hasil dari handler-nya .On .

Ada dua cara untuk menggunakan API di server.

Anda dapat memanggil Client(...) atau Caller pada properti Clients dalam metode Hub:

public class ChatHub : Hub
{
    public async Task<string> WaitForMessage(string connectionId)
    {
        var message = await Clients.Client(connectionId).InvokeAsync<string>(
            "GetMessage");
        return message;
    }
}

Atau, Anda dapat memanggil Client(...) pada instance dari IHubContext<T>:

async Task SomeMethod(IHubContext<MyHub> context)
{
    string result = await context.Clients.Client(connectionID).InvokeAsync<string>(
        "GetMessage");
}

Hub bertipe kuat juga dapat mengembalikan nilai dari metode antarmuka:

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

Klien mengembalikan hasil dalam handler mereka .On(...) , seperti yang ditunjukkan di bagian berikut.

Klien .NET

hubConnection.On("GetMessage", async () =>
{
    Console.WriteLine("Enter message:");
    var message = await Console.In.ReadLineAsync();
    return message;
});

Klien TypeScript

hubConnection.on("GetMessage", async () => {
    let promise = new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve("message");
        }, 100);
    });
    return promise;
});

Klien Java

hubConnection.onWithResult("GetMessage", () -> {
    return Single.just("message");
});

Mengubah nama metode hub

Secara default, nama metode hub server adalah nama metode .NET. Untuk mengubah perilaku default ini untuk metode tertentu, gunakan atribut HubMethodName . Klien harus menggunakan nama ini alih-alih nama metode .NET saat memanggil metode:

[HubMethodName("SendMessageToUser")]
public async Task DirectMessage(string user, string message)
    => await Clients.User(user).SendAsync("ReceiveMessage", user, message);

Menyuntikkan layanan ke hub

Konstruktor hub dapat menerima layanan dari injeksi dependensi sebagai parameter, yang kemudian dapat disimpan sebagai properti kelas untuk digunakan di metode hub.

Saat Anda menyuntikkan beberapa layanan untuk metode hub yang berbeda atau sebagai cara alternatif menulis kode, metode hub juga dapat menerima layanan dari injeksi dependensi. Secara bawaan, parameter metode hub diperiksa dan diresolusikan melalui injeksi dependensi jika memungkinkan.

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

Jika resolusi implisit parameter dari layanan tidak diinginkan, Anda dapat menonaktifkan perilaku dengan opsi server DisableImplicitFromServicesParameters .

Untuk secara eksplisit menentukan parameter mana yang diselesaikan dari injeksi dependensi dalam metode hub, gunakan properti DisableImplicitFromServicesParameters . Tentukan atribut [FromServices] atau atribut kustom yang mengimplementasikan IFromServiceMetadata pada parameter metode hub yang harus diatasi melalui injeksi dependensi.

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

Note

Fitur ini menggunakan IServiceProviderIsService, yang secara opsional diimplementasikan dalam konfigurasi injeksi dependensi. Jika kontainer injeksi dependensi aplikasi tidak mendukung fitur ini, memasukkan layanan ke metode hub tidak didukung.

Dukungan layanan utama dalam injeksi dependensi

Mekanisme layanan berkunci memungkinkan Anda mendaftarkan dan mengambil layanan injeksi dependensi menggunakan kunci. Layanan diasosiasikan dengan sebuah kunci dengan memanggil metode AddKeyedSingleton untuk mendaftarkannya. Sebagai alternatif, Anda dapat memanggil AddKeyedScoped metode atau AddKeyedTransient .

Anda mengakses layanan terdaftar dengan menentukan kunci dengan atribut [FromKeyedServices]. Kode berikut menunjukkan cara menggunakan layanan kunci:

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

Batas pemanggilan streaming per koneksi

MaximumParallelInvocationsPerClient mengatur jumlah pemanggilan metode hub non-streaming yang dapat dijalankan oleh klien secara paralel sebelum dimasukkan ke antrean. Ini tidak berlaku untuk pemanggilan hub streaming. Pemanggilan streaming sengaja dikecualikan karena diharapkan berjalan lama dan bersamaan, sehingga klien dapat memulai sejumlah aliran bersamaan terlepas dari pengaturan tersebut.

Untuk menerapkan batas per koneksi pada pemanggilan streaming, bungkus stream di dalam metode hub itu sendiri dengan menggunakan metode bantu privat yang menambah nilai penghitung sebelum menghasilkan item dan mengurangi nilainya dalam blok finally:

using System.Collections.Concurrent;
using System.Runtime.CompilerServices;

public class StreamingHub : Hub
{
    private static readonly ConcurrentDictionary<string, int> _activeStreams = new();
    private const int MaxConcurrentStreams = 2;

    public IAsyncEnumerable<int> Counter(
        int count,
        int delay,
        CancellationToken cancellationToken)
    {
        return WithLimit(Context.ConnectionId, GetCounter(count, delay, cancellationToken));
    }

    private async IAsyncEnumerable<int> GetCounter(
        int count,
        int delay,
        [EnumeratorCancellation] CancellationToken cancellationToken)
    {
        for (var i = 0; i < count; i++)
        {
            cancellationToken.ThrowIfCancellationRequested();
            yield return i;
            await Task.Delay(delay, cancellationToken);
        }
    }

    private async IAsyncEnumerable<T> WithLimit(
        string connectionId,
        IAsyncEnumerable<T> stream,
        [EnumeratorCancellation] CancellationToken cancellationToken = default)
    {
        var current = _activeStreams.AddOrUpdate(
            connectionId,
            addValue: 1,
            updateValueFactory: (_, count) => count + 1);

        if (current > MaxConcurrentStreams)
        {
            Decrement(connectionId);
            throw new HubException(
                $"The connection is limited to {MaxConcurrentStreams} concurrent streaming invocations.");
        }

        try
        {
            await foreach (var item in stream.WithCancellation(cancellationToken))
            {
                yield return item;
            }
        }
        finally
        {
            Decrement(connectionId);
        }
    }

    private static void Decrement(string connectionId)
    {
        while (_activeStreams.TryGetValue(connectionId, out var current))
        {
            if (current <= 1)
            {
                if (_activeStreams.TryRemove(new KeyValuePair<string, int>(connectionId, current)))
                {
                    return;
                }
            }
            else if (_activeStreams.TryUpdate(connectionId, current - 1, current))
            {
                return;
            }
        }
    }
}

Poin utamanya adalah bahwa WithLimit membungkus IAsyncEnumerable<T> asli dan mempertahankan penghitung tetap meningkat selama seluruh masa aktif stream, bukan hanya sampai item pertama dikembalikan. Blok finally hanya berjalan ketika klien selesai menerima aliran data, membatalkan aliran tersebut, atau koneksi terputus.

Jika metode pada hub streaming Anda mengembalikan ChannelReader<T> alih-alih IAsyncEnumerable<T>, wrapper serupa dapat diterapkan. Ini harus menggunakan dictionary _activeStreams yang sama agar kedua jenis aliran berbagi satu batas pada tingkat koneksi, alih-alih masing-masing memiliki hitungan independen sendiri.

Note

_activeStreams Kamus ini static sehingga digunakan bersama di semua instans hub. Jika Anda lebih memilih state yang dikelola oleh DI, daftarkan layanan singleton yang mengelola kamus tersebut dan injeksikan layanan itu ke dalam konstruktor hub.

Menangani peristiwa untuk koneksi

SignalR HUBS API menyediakan OnConnectedAsync metode virtual dan OnDisconnectedAsync untuk mengelola dan melacak koneksi. Ambil alih OnConnectedAsync metode virtual untuk melakukan tindakan saat klien tersambung ke hub, seperti menambahkannya ke grup:

public override async Task OnConnectedAsync()
{
    await Groups.AddToGroupAsync(Context.ConnectionId, "SignalR Users");
    await base.OnConnectedAsync();
}

Ambil alih OnDisconnectedAsync metode virtual untuk melakukan tindakan saat klien terputus. Jika klien memutuskan sambungan dengan sengaja, seperti dengan memanggil connection.stop(), exception parameter diatur ke null. Namun, jika klien terputus karena kesalahan, seperti kegagalan jaringan, exception parameter berisi pengecualian yang menjelaskan kegagalan:

public override async Task OnDisconnectedAsync(Exception? exception)
{
    await base.OnDisconnectedAsync(exception);
}

Metode RemoveFromGroupAsync ini tidak perlu dipanggil dalam OnDisconnectedAsync metode karena ditangani secara otomatis.

Menangani kesalahan

Pengecualian yang dilemparkan pada metode hub akan dikirimkan kepada klien yang memanggilnya. Pada klien JavaScript, invoke metode mengembalikan objek 'Janji' JavaScript. Klien dapat melampirkan catch handler ke janji yang dikembalikan atau digunakan try/catchdengan async/await untuk menangani pengecualian:

try {
  await connection.invoke("SendMessage", user, message);
} catch (err) {
  console.error(err);
}

Koneksi tidak ditutup saat hub menghasilkan pengecualian. Secara default, SignalR mengembalikan pesan kesalahan umum kepada klien, seperti yang ditunjukkan dalam contoh berikut:

Microsoft.AspNetCore.SignalR.HubException: An unexpected error occurred invoking 'SendMessage' on the server.

Pengecualian tak terduga sering berisi informasi sensitif, seperti nama server database dalam pengecualian yang dipicu ketika koneksi database gagal. Sebagai langkah keamanan, SignalR tidak mengekspos pesan kesalahan terperinci ini secara default. Untuk informasi selengkapnya tentang mengapa detail pengecualian ditekan, lihat Pertimbangan keamanan di ASP.NET Core SignalR.

Jika kondisi luar biasa harus disebarkan ke klien, gunakan HubException kelas . HubException Jika dilemparkan dalam metode hub, SignalRmengirim seluruh pesan pengecualian ke klien dalam bentuk yang tidak dimodifikasi:

public Task ThrowException()
    => throw new HubException("This error will be sent to the client!");

Note

SignalR hanya mengirim Message properti pengecualian ke klien. Jejak tumpukan dan properti lainnya pada pengecualian tidak dapat diakses oleh klien.

Oleh Rachel Appel dan Kevin Griffin

SignalR HUBS API memungkinkan klien yang terhubung untuk memanggil metode di server, memfasilitasi komunikasi real-time. Server mendefinisikan metode yang dipanggil oleh klien, dan klien menentukan metode yang dipanggil oleh server. SignalR juga memungkinkan komunikasi klien-ke-klien tidak langsung, selalu dimediasi oleh SignalR Hub, memungkinkan pesan dikirim antara klien individu, grup, atau ke semua klien yang terhubung. SignalR mengurus semua yang diperlukan untuk memungkinkan komunikasi klien-ke-server dan server-ke-klien secara real-time.

Mengonfigurasi SignalR hub

Untuk mendaftarkan layanan yang diperlukan oleh SignalR hub, panggil AddSignalR di Program.cs:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddSignalR();

Untuk mengonfigurasi titik akhir SignalR, panggil MapHub di Program.cs juga:

app.MapRazorPages();
app.MapHub<ChatHub>("/Chat");

app.Run();

Note

ASP.NET Core SignalR komponen sisi server sekarang diinstal dengan .NET Core SDK. Untuk informasi selengkapnya, lihat SignalR rakitan dalam kerangka kerja bersama.

Membuat dan menggunakan hub

Buat hub dengan mendeklarasikan kelas yang mewarisi dari Hub. Tambahkan public metode ke kelas untuk membuatnya dapat dipanggil dari klien:

public class ChatHub : Hub
{
    public async Task SendMessage(string user, string message)
        => await Clients.All.SendAsync("ReceiveMessage", user, message);
}

Note

Hub bersifat sementara:

  • Jangan menyimpan status di properti kelas hub. Setiap panggilan metode hub dijalankan pada instans hub baru.
  • Jangan membuat instans hub secara langsung melalui injeksi dependensi. Untuk mengirim pesan ke klien dari tempat lain di aplikasi Anda, gunakan IHubContext.
  • Gunakan await saat memanggil metode asinkron yang bergantung pada hub tetap hidup. Misalnya, metode seperti Clients.All.SendAsync(...) dapat gagal jika dipanggil tanpa await dan metode hub selesai sebelum SendAsync selesai.

Objek Konteks

Kelas Hub menyertakan Context properti yang berisi properti berikut dengan informasi tentang koneksi:

Property Description
ConnectionId Mendapatkan ID unik untuk koneksi, yang ditetapkan oleh SignalR. Ada satu ID koneksi untuk setiap koneksi.
UserIdentifier Mendapatkan pengidentifikasi pengguna. Secara default, SignalR menggunakan ClaimTypes.NameIdentifier dari yang ClaimsPrincipal terkait dengan koneksi sebagai pengidentifikasi pengguna.
User Mendapatkan ClaimsPrincipal yang terkait dengan pengguna saat ini.
Items Mendapatkan kumpulan kunci/nilai yang dapat digunakan untuk berbagi data dalam cakupan koneksi ini. Data dapat disimpan dalam kumpulan ini dan akan tetap ada untuk koneksi selama berbagai pemanggilan metode hub.
Features Mendapatkan kumpulan fitur yang tersedia pada koneksi. Untuk saat ini, koleksi ini tidak diperlukan dalam sebagian besar skenario, sehingga belum didokumenkan secara rinci.
ConnectionAborted Mendapatkan sebuah CancellationToken yang memberi tahu ketika koneksi dibatalkan.

Hub.Context juga berisi metode berikut:

Method Description
GetHttpContext Mengembalikan HttpContext untuk koneksi, atau null jika koneksi tidak terkait dengan permintaan HTTP. Untuk koneksi HTTP, gunakan metode ini untuk mendapatkan informasi seperti header HTTP dan string kueri.
Abort Membatalkan koneksi.

Objek Klien (Clients object)

Kelas Hub menyertakan Clients properti yang berisi properti berikut untuk komunikasi antara server dan klien:

Property Description
All Menjalankan metode pada semua klien yang terhubung
Caller Memanggil metode pada klien yang memanggil metode hub
Others Memanggil metode pada semua klien yang terhubung kecuali klien yang memanggil metode

Hub.Clients juga berisi metode berikut:

Method Description
AllExcept Memanggil metode pada semua klien yang terhubung kecuali untuk koneksi yang ditentukan
Client Memanggil metode pada klien terhubung tertentu
Clients Memanggil metode pada klien tertentu yang terhubung
Group Memanggil metode pada semua koneksi dalam grup yang ditentukan
GroupExcept Memanggil metode pada semua koneksi dalam grup yang ditentukan, kecuali koneksi yang ditentukan
Groups Memanggil metode pada beberapa grup koneksi
OthersInGroup Memanggil metode pada sekelompok koneksi, tidak termasuk klien yang memanggil metode hub
User Memanggil metode pada semua koneksi yang terkait dengan pengguna tertentu
Users Memanggil metode pada semua koneksi yang terkait dengan pengguna yang ditentukan

Setiap properti atau metode dalam tabel sebelumnya mengembalikan objek dengan SendAsync metode . Metode SendAsync menerima nama metode klien yang akan dipanggil serta parameter apa pun.

Objek yang dikembalikan oleh metode Client dan Caller juga berisi metode InvokeAsync, yang dapat digunakan untuk menunggu hasil dari klien.

Mengirim pesan ke klien

Untuk melakukan panggilan ke klien tertentu, gunakan properti Clients objek. Dalam contoh berikut, ada tiga metode hub:

  • SendMessage mengirim pesan ke semua klien yang terhubung, menggunakan Clients.All.
  • SendMessageToCaller mengirim pesan kembali ke pemanggil, menggunakan Clients.Caller.
  • SendMessageToGroup mengirim pesan ke semua klien dalam SignalR Users grup.
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);

Hub dengan tiped kuat

Kelemahan penggunaannya SendAsync adalah mengandalkan string untuk menentukan metode klien yang akan dipanggil. Ini membuat kode terbuka untuk kesalahan runtime jika nama metode salah eja atau hilang dari klien.

Alternatif untuk menggunakan SendAsync adalah mengetik Hub kelas dengan kuat dengan Hub<T>. Dalam contoh berikut, ChatHub metode klien telah diekstraksi ke antarmuka yang disebut IChatClient:

public interface IChatClient
{
    Task ReceiveMessage(string user, string message);
}

Antarmuka ini dapat digunakan untuk merefaktor contoh ChatHub sebelumnya menjadi bertipe tegas.

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

Menggunakan Hub<IChatClient> mengaktifkan pemeriksaan waktu kompilasi metode klien. Ini mencegah masalah yang disebabkan oleh penggunaan string, karena Hub<T> hanya dapat menyediakan akses ke metode yang ditentukan dalam antarmuka. Menggunakan Hub<T> yang bertipe kuat menonaktifkan kemampuan untuk menggunakan SendAsync.

Note

Akhiran Async tidak dihapus dari nama metode. Kecuali metode klien didefinisikan dengan .on('MyMethodAsync'), jangan gunakan MyMethodAsync sebagai nama.

Hasil klien

Selain melakukan panggilan ke klien, server dapat meminta hasil dari klien. Ini mengharuskan server untuk menggunakan ISingleClientProxy.InvokeAsync dan klien untuk mengembalikan hasil dari handler-nya .On .

Ada dua cara untuk menggunakan API di server, yang pertama adalah memanggil Client(...) atau Caller pada Clients properti dalam metode Hub:

public class ChatHub : Hub
{
    public async Task<string> WaitForMessage(string connectionId)
    {
        var message = await Clients.Client(connectionId).InvokeAsync<string>(
            "GetMessage");
        return message;
    }
}

Cara kedua adalah memanggil Client(...) pada instans IHubContext<T>:

async Task SomeMethod(IHubContext<MyHub> context)
{
    string result = await context.Clients.Client(connectionID).InvokeAsync<string>(
        "GetMessage");
}

Hub bertipe kuat juga dapat mengembalikan nilai dari metode antarmuka.

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

Klien mengembalikan hasil dalam handler mereka .On(...) , seperti yang ditunjukkan di bawah ini:

Klien .NET

hubConnection.On("GetMessage", async () =>
{
    Console.WriteLine("Enter message:");
    var message = await Console.In.ReadLineAsync();
    return message;
});

Klien TypeScript

hubConnection.on("GetMessage", async () => {
    let promise = new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve("message");
        }, 100);
    });
    return promise;
});

Klien Java

hubConnection.onWithResult("GetMessage", () -> {
    return Single.just("message");
});

Mengubah nama metode hub

Secara default, nama metode hub server adalah nama metode .NET. Untuk mengubah perilaku default ini untuk metode tertentu, gunakan atribut HubMethodName . Klien harus menggunakan nama ini alih-alih nama metode .NET saat memanggil metode:

[HubMethodName("SendMessageToUser")]
public async Task DirectMessage(string user, string message)
    => await Clients.User(user).SendAsync("ReceiveMessage", user, message);

Menyuntikkan layanan ke hub

Konstruktor hub dapat menerima layanan dari DI sebagai parameter, yang dapat disimpan di properti di kelas untuk digunakan dalam metode hub.

Saat menyuntikkan beberapa layanan untuk metode hub yang berbeda atau sebagai cara alternatif menulis kode, metode hub juga dapat menerima layanan dari DI. Secara default, parameter metode hub diperiksa dan diselesaikan dari DI jika memungkinkan.

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

Jika resolusi implisit parameter dari layanan tidak diinginkan, nonaktifkan dengan DisableImplicitFromServicesParameters. Untuk secara eksplisit menentukan parameter mana yang diselesaikan dari DI dalam metode hub, gunakan DisableImplicitFromServicesParameters opsi dan gunakan [FromServices] atribut atau atribut kustom yang menerapkan IFromServiceMetadata pada parameter metode hub yang harus diselesaikan dari 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);
    }
}

Note

Fitur ini memanfaatkan IServiceProviderIsService, yang secara opsional diimplementasikan oleh implementasi DI. Jika kontainer DI aplikasi tidak mendukung fitur ini, memasukkan layanan ke metode hub tidak didukung.

Menangani peristiwa untuk koneksi

SignalR HUBS API menyediakan OnConnectedAsync metode virtual dan OnDisconnectedAsync untuk mengelola dan melacak koneksi. Ambil alih OnConnectedAsync metode virtual untuk melakukan tindakan saat klien tersambung ke hub, seperti menambahkannya ke grup:

public override async Task OnConnectedAsync()
{
    await Groups.AddToGroupAsync(Context.ConnectionId, "SignalR Users");
    await base.OnConnectedAsync();
}

Ambil alih OnDisconnectedAsync metode virtual untuk melakukan tindakan saat klien terputus. Jika klien memutuskan sambungan dengan sengaja, seperti dengan memanggil connection.stop(), exception parameter diatur ke null. Namun, jika klien terputus karena kesalahan, seperti kegagalan jaringan, exception parameter berisi pengecualian yang menjelaskan kegagalan:

public override async Task OnDisconnectedAsync(Exception? exception)
{
    await base.OnDisconnectedAsync(exception);
}

RemoveFromGroupAsync tidak perlu dipanggil dalam OnDisconnectedAsync, secara otomatis ditangani untuk Anda.

Menangani kesalahan

Pengecualian yang dilemparkan pada metode hub akan dikirimkan kepada klien yang memanggilnya. Pada klien JavaScript, invoke metode mengembalikan JavaScript Promise. Klien dapat melampirkan catch handler ke janji yang dikembalikan atau digunakan try/catchdengan async/await untuk menangani pengecualian:

try {
  await connection.invoke("SendMessage", user, message);
} catch (err) {
  console.error(err);
}

Koneksi tidak ditutup saat hub menghasilkan pengecualian. Secara default, SignalR mengembalikan pesan kesalahan umum kepada klien, seperti yang ditunjukkan dalam contoh berikut:

Microsoft.AspNetCore.SignalR.HubException: An unexpected error occurred invoking 'SendMessage' on the server.

Pengecualian tak terduga sering berisi informasi sensitif, seperti nama server database dalam pengecualian yang dipicu ketika koneksi database gagal. SignalR tidak mengekspos pesan kesalahan terperinci ini secara default sebagai ukuran keamanan. Untuk informasi selengkapnya tentang mengapa detail pengecualian ditekan, lihat Pertimbangan keamanan di ASP.NET Core SignalR.

Jika kondisi luar biasa harus disebarkan ke klien, gunakan HubException kelas . HubException Jika dilemparkan dalam metode hub, SignalRmengirim seluruh pesan pengecualian ke klien, tidak dimodifikasi:

public Task ThrowException()
    => throw new HubException("This error will be sent to the client!");

Note

SignalR hanya mengirim Message properti pengecualian ke klien. Jejak tumpukan dan properti lainnya pada pengecualian tidak dapat diakses oleh klien.

Sumber daya tambahan

Oleh Rachel Appel dan Kevin Griffin

SignalR HUBS API memungkinkan klien yang terhubung untuk memanggil metode di server, memfasilitasi komunikasi real-time. Server mendefinisikan metode yang dipanggil oleh klien, dan klien menentukan metode yang dipanggil oleh server. SignalR juga memungkinkan komunikasi klien-ke-klien tidak langsung, selalu dimediasi oleh SignalR Hub, memungkinkan pesan dikirim antara klien individu, grup, atau ke semua klien yang terhubung. SignalR mengurus semua yang diperlukan untuk memungkinkan komunikasi klien-ke-server dan server-ke-klien secara real-time.

Mengonfigurasi SignalR hub

Untuk mendaftarkan layanan yang diperlukan oleh SignalR hub, panggil AddSignalR di Program.cs:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddSignalR();

Untuk mengonfigurasi titik akhir SignalR, panggil MapHub di Program.cs juga:

app.MapRazorPages();
app.MapHub<ChatHub>("/Chat");

app.Run();

Note

ASP.NET Core SignalR komponen sisi server sekarang diinstal dengan .NET Core SDK. Untuk informasi selengkapnya, lihat SignalR rakitan dalam kerangka kerja bersama.

Membuat dan menggunakan hub

Buat hub dengan mendeklarasikan kelas yang mewarisi dari Hub. Tambahkan public metode ke kelas untuk membuatnya dapat dipanggil dari klien:

public class ChatHub : Hub
{
    public async Task SendMessage(string user, string message)
        => await Clients.All.SendAsync("ReceiveMessage", user, message);
}

Note

Hub bersifat sementara:

  • Jangan menyimpan status di properti kelas hub. Setiap panggilan metode hub dijalankan pada instans hub baru.
  • Jangan membuat instans hub secara langsung melalui injeksi dependensi. Untuk mengirim pesan ke klien dari tempat lain di aplikasi Anda, gunakan IHubContext.
  • Gunakan await saat memanggil metode asinkron yang bergantung pada hub tetap hidup. Misalnya, metode seperti Clients.All.SendAsync(...) dapat gagal jika dipanggil tanpa await dan metode hub selesai sebelum SendAsync selesai.

Objek Konteks

Kelas Hub menyertakan Context properti yang berisi properti berikut dengan informasi tentang koneksi:

Property Description
ConnectionId Mendapatkan ID unik untuk koneksi, yang ditetapkan oleh SignalR. Ada satu ID koneksi untuk setiap koneksi.
UserIdentifier Mendapatkan pengidentifikasi pengguna. Secara default, SignalR menggunakan ClaimTypes.NameIdentifier dari yang ClaimsPrincipal terkait dengan koneksi sebagai pengidentifikasi pengguna.
User Mendapatkan ClaimsPrincipal yang terkait dengan pengguna saat ini.
Items Mendapatkan kumpulan kunci/nilai yang dapat digunakan untuk berbagi data dalam cakupan koneksi ini. Data dapat disimpan dalam kumpulan ini dan akan tetap ada untuk koneksi selama berbagai pemanggilan metode hub.
Features Mendapatkan kumpulan fitur yang tersedia pada koneksi. Untuk saat ini, koleksi ini tidak diperlukan dalam sebagian besar skenario, sehingga belum didokumenkan secara rinci.
ConnectionAborted Mendapatkan sebuah CancellationToken yang memberi tahu ketika koneksi dibatalkan.

Hub.Context juga berisi metode berikut:

Method Description
GetHttpContext Mengembalikan HttpContext untuk koneksi, atau null jika koneksi tidak terkait dengan permintaan HTTP. Untuk koneksi HTTP, gunakan metode ini untuk mendapatkan informasi seperti header HTTP dan string kueri.
Abort Membatalkan koneksi.

Objek Klien (Clients object)

Kelas Hub menyertakan Clients properti yang berisi properti berikut untuk komunikasi antara server dan klien:

Property Description
All Menjalankan metode pada semua klien yang terhubung
Caller Memanggil metode pada klien yang memanggil metode hub
Others Memanggil metode pada semua klien yang terhubung kecuali klien yang memanggil metode

Hub.Clients juga berisi metode berikut:

Method Description
AllExcept Memanggil metode pada semua klien yang terhubung kecuali untuk koneksi yang ditentukan
Client Memanggil metode pada klien terhubung tertentu
Clients Memanggil metode pada klien tertentu yang terhubung
Group Memanggil metode pada semua koneksi dalam grup yang ditentukan
GroupExcept Memanggil metode pada semua koneksi dalam grup yang ditentukan, kecuali koneksi yang ditentukan
Groups Memanggil metode pada beberapa grup koneksi
OthersInGroup Memanggil metode pada sekelompok koneksi, tidak termasuk klien yang memanggil metode hub
User Memanggil metode pada semua koneksi yang terkait dengan pengguna tertentu
Users Memanggil metode pada semua koneksi yang terkait dengan pengguna yang ditentukan

Setiap properti atau metode dalam tabel sebelumnya mengembalikan objek dengan SendAsync metode . Metode SendAsync menerima nama metode klien yang akan dipanggil serta parameter apa pun.

Mengirim pesan ke klien

Untuk melakukan panggilan ke klien tertentu, gunakan properti Clients objek. Dalam contoh berikut, ada tiga metode hub:

  • SendMessage mengirim pesan ke semua klien yang terhubung, menggunakan Clients.All.
  • SendMessageToCaller mengirim pesan kembali ke pemanggil, menggunakan Clients.Caller.
  • SendMessageToGroup mengirim pesan ke semua klien dalam SignalR Users grup.
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);

Hub dengan tiped kuat

Kelemahan penggunaannya SendAsync adalah mengandalkan string untuk menentukan metode klien yang akan dipanggil. Ini membuat kode terbuka untuk kesalahan runtime jika nama metode salah eja atau hilang dari klien.

Alternatif untuk menggunakan SendAsync adalah mengetik Hub kelas dengan kuat dengan Hub<T>. Dalam contoh berikut, ChatHub metode klien telah diekstraksi ke antarmuka yang disebut IChatClient:

public interface IChatClient
{
    Task ReceiveMessage(string user, string message);
}

Antarmuka ini dapat digunakan untuk merefaktor contoh ChatHub sebelumnya menjadi bertipe tegas.

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

Menggunakan Hub<IChatClient> mengaktifkan pemeriksaan waktu kompilasi metode klien. Ini mencegah masalah yang disebabkan oleh penggunaan string, karena Hub<T> hanya dapat menyediakan akses ke metode yang ditentukan dalam antarmuka. Menggunakan Hub<T> yang bertipe kuat menonaktifkan kemampuan untuk menggunakan SendAsync.

Note

Akhiran Async tidak dihapus dari nama metode. Kecuali metode klien didefinisikan dengan .on('MyMethodAsync'), jangan gunakan MyMethodAsync sebagai nama.

Mengubah nama metode hub

Secara default, nama metode hub server adalah nama metode .NET. Untuk mengubah perilaku default ini untuk metode tertentu, gunakan atribut HubMethodName . Klien harus menggunakan nama ini alih-alih nama metode .NET saat memanggil metode:

[HubMethodName("SendMessageToUser")]
public async Task DirectMessage(string user, string message)
    => await Clients.User(user).SendAsync("ReceiveMessage", user, message);

Menangani peristiwa untuk koneksi

SignalR HUBS API menyediakan OnConnectedAsync metode virtual dan OnDisconnectedAsync untuk mengelola dan melacak koneksi. Ambil alih OnConnectedAsync metode virtual untuk melakukan tindakan saat klien tersambung ke hub, seperti menambahkannya ke grup:

public override async Task OnConnectedAsync()
{
    await Groups.AddToGroupAsync(Context.ConnectionId, "SignalR Users");
    await base.OnConnectedAsync();
}

Ambil alih OnDisconnectedAsync metode virtual untuk melakukan tindakan saat klien terputus. Jika klien memutuskan sambungan dengan sengaja, seperti dengan memanggil connection.stop(), exception parameter diatur ke null. Namun, jika klien terputus karena kesalahan, seperti kegagalan jaringan, exception parameter berisi pengecualian yang menjelaskan kegagalan:

public override async Task OnDisconnectedAsync(Exception? exception)
{
    await base.OnDisconnectedAsync(exception);
}

RemoveFromGroupAsync tidak perlu dipanggil dalam OnDisconnectedAsync, secara otomatis ditangani untuk Anda.

Menangani kesalahan

Pengecualian yang dilemparkan pada metode hub akan dikirimkan kepada klien yang memanggilnya. Pada klien JavaScript, invoke metode mengembalikan JavaScript Promise. Klien dapat melampirkan catch handler ke janji yang dikembalikan atau digunakan try/catchdengan async/await untuk menangani pengecualian:

try {
  await connection.invoke("SendMessage", user, message);
} catch (err) {
  console.error(err);
}

Koneksi tidak ditutup saat hub menghasilkan pengecualian. Secara default, SignalR mengembalikan pesan kesalahan umum kepada klien, seperti yang ditunjukkan dalam contoh berikut:

Microsoft.AspNetCore.SignalR.HubException: An unexpected error occurred invoking 'SendMessage' on the server.

Pengecualian tak terduga sering berisi informasi sensitif, seperti nama server database dalam pengecualian yang dipicu ketika koneksi database gagal. SignalR tidak mengekspos pesan kesalahan terperinci ini secara default sebagai ukuran keamanan. Untuk informasi selengkapnya tentang mengapa detail pengecualian ditekan, lihat Pertimbangan keamanan di ASP.NET Core SignalR.

Jika kondisi luar biasa harus disebarkan ke klien, gunakan HubException kelas . HubException Jika dilemparkan dalam metode hub, SignalRmengirim seluruh pesan pengecualian ke klien, tidak dimodifikasi:

public Task ThrowException()
    => throw new HubException("This error will be sent to the client!");

Note

SignalR hanya mengirim Message properti pengecualian ke klien. Jejak tumpukan dan properti lainnya pada pengecualian tidak dapat diakses oleh klien.

Sumber daya tambahan

Oleh Rachel Appel dan Kevin Griffin

Melihat atau mengunduh kode sampel (cara mengunduh)

Apa itu SignalR hub

SignalR HUBS API memungkinkan klien yang terhubung untuk memanggil metode di server, memfasilitasi komunikasi real-time. Server mendefinisikan metode yang dipanggil oleh klien, dan klien menentukan metode yang dipanggil oleh server. SignalR juga memungkinkan komunikasi klien-ke-klien tidak langsung, selalu dimediasi oleh SignalR Hub, memungkinkan pesan dikirim antara klien individu, grup, atau ke semua klien yang terhubung. SignalR mengurus semua yang diperlukan untuk memungkinkan komunikasi klien-ke-server dan server-ke-klien secara real-time.

Mengonfigurasi SignalR hub

Middleware SignalR memerlukan beberapa layanan, yang dikonfigurasi dengan memanggil AddSignalR:

services.AddSignalR();

Saat menambahkan SignalR fungsionalitas ke aplikasi ASP.NET Core, siapkan SignalR rute dengan memanggil MapHub dalam callback di metode Startup.ConfigureUseEndpoints:

app.UseRouting();
app.UseEndpoints(endpoints =>
{
    endpoints.MapHub<ChatHub>("/chathub");
});

Note

ASP.NET Core SignalR komponen sisi server sekarang diinstal dengan .NET Core SDK. Untuk informasi selengkapnya, lihat SignalR rakitan dalam kerangka kerja bersama.

Membuat dan menggunakan hub

Buat hub dengan mendeklarasikan kelas yang mewarisi dari Hub, dan menambahkan metode publik ke dalamnya. Klien dapat memanggil metode yang didefinisikan sebagai public:

public class ChatHub : Hub
{
    public Task SendMessage(string user, string message)
    {
        return Clients.All.SendAsync("ReceiveMessage", user, message);
    }
}

Anda dapat menentukan jenis pengembalian dan parameter, termasuk jenis dan array kompleks, seperti yang Anda lakukan dalam metode C# apa pun. SignalR menangani serialisasi dan deserialisasi objek dan array kompleks dalam parameter Anda dan mengembalikan nilai.

Note

Hub bersifat sementara:

  • Jangan menyimpan state dalam properti pada kelas hub. Setiap panggilan metode hub dijalankan pada instans hub baru.
  • Jangan membuat instans hub secara langsung melalui injeksi dependensi. Untuk mengirim pesan ke klien dari tempat lain di aplikasi Anda, gunakan IHubContext.
  • Gunakan await saat memanggil metode asinkron yang bergantung pada hub tetap hidup. Misalnya, metode seperti Clients.All.SendAsync(...) dapat gagal jika dipanggil tanpa await dan metode hub selesai sebelum SendAsync selesai.

Objek Konteks

Kelas Hub memiliki Context properti yang berisi properti berikut dengan informasi tentang koneksi:

Property Description
ConnectionId Mendapatkan ID unik untuk koneksi, yang ditetapkan oleh SignalR. Ada satu ID koneksi untuk setiap koneksi.
UserIdentifier Mendapatkan pengidentifikasi pengguna. Secara default, SignalR menggunakan ClaimTypes.NameIdentifier dari yang ClaimsPrincipal terkait dengan koneksi sebagai pengidentifikasi pengguna.
User Mendapatkan ClaimsPrincipal yang terkait dengan pengguna saat ini.
Items Mendapatkan kumpulan kunci/nilai yang dapat digunakan untuk berbagi data dalam cakupan koneksi ini. Data dapat disimpan dalam kumpulan ini dan akan tetap ada untuk koneksi selama berbagai pemanggilan metode hub.
Features Mendapatkan kumpulan fitur yang tersedia pada koneksi. Untuk saat ini, koleksi ini tidak diperlukan dalam sebagian besar skenario, sehingga belum didokumenkan secara rinci.
ConnectionAborted Mendapatkan sebuah CancellationToken yang memberi tahu ketika koneksi dibatalkan.

Hub.Context juga berisi metode berikut:

Method Description
GetHttpContext Mengembalikan HttpContext untuk koneksi, atau null jika koneksi tidak terkait dengan permintaan HTTP. Untuk koneksi HTTP, Anda dapat menggunakan metode ini untuk mendapatkan informasi seperti header HTTP dan string kueri.
Abort Membatalkan koneksi.

Objek Klien (Clients object)

Kelas Hub memiliki Clients properti yang berisi properti berikut untuk komunikasi antara server dan klien:

Property Description
All Menjalankan metode pada semua klien yang terhubung
Caller Memanggil metode pada klien yang memanggil metode hub
Others Memanggil metode pada semua klien yang terhubung kecuali klien yang memanggil metode

Hub.Clients juga berisi metode berikut:

Method Description
AllExcept Memanggil metode pada semua klien yang terhubung kecuali untuk koneksi yang ditentukan
Client Memanggil metode pada klien terhubung tertentu
Clients Memanggil metode pada klien tertentu yang terhubung
Group Memanggil metode pada semua koneksi dalam grup yang ditentukan
GroupExcept Memanggil metode pada semua koneksi dalam grup yang ditentukan, kecuali koneksi yang ditentukan
Groups Memanggil metode pada beberapa grup koneksi
OthersInGroup Memanggil metode pada sekelompok koneksi, tidak termasuk klien yang memanggil metode hub
User Memanggil metode pada semua koneksi yang terkait dengan pengguna tertentu
Users Memanggil metode pada semua koneksi yang terkait dengan pengguna yang ditentukan

Setiap properti atau metode dalam tabel sebelumnya mengembalikan objek dengan SendAsync metode . Metode SendAsync memungkinkan Anda memberikan nama dan parameter dari metode klien yang akan dipanggil.

Mengirim pesan ke klien

Untuk melakukan panggilan ke klien tertentu, gunakan properti Clients objek. Dalam contoh berikut, ada tiga metode Hub:

  • SendMessage mengirim pesan ke semua klien yang terhubung, menggunakan Clients.All.
  • SendMessageToCaller mengirim pesan kembali ke pemanggil, menggunakan Clients.Caller.
  • SendMessageToGroup mengirim pesan ke semua klien dalam SignalR Users grup.
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);
}

Hub dengan tiped kuat

Kelemahan penggunaannya SendAsync adalah mengandalkan string ajaib untuk menentukan metode klien yang akan dipanggil. Ini membuat kode terbuka untuk kesalahan runtime jika nama metode salah eja atau hilang dari klien.

Alternatif untuk menggunakan SendAsync adalah mengetik Hub dengan kuat dengan Hub<T>. Dalam contoh berikut, ChatHub metode klien telah diekstraksi ke antarmuka yang disebut IChatClient.

public interface IChatClient
{
    Task ReceiveMessage(string user, string message);
}

Antarmuka ini dapat digunakan untuk merefaktor contoh sebelumnya 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);
        }
}

Menggunakan Hub<IChatClient> mengaktifkan pemeriksaan waktu kompilasi metode klien. Ini mencegah masalah yang disebabkan oleh penggunaan string ajaib, karena Hub<T> hanya dapat menyediakan akses ke metode yang ditentukan dalam antarmuka.

Menggunakan Hub<T> yang bertipe kuat menonaktifkan kemampuan untuk menggunakan SendAsync. Metode apa pun yang ditentukan pada antarmuka masih dapat didefinisikan sebagai asinkron. Bahkan, masing-masing metode ini harus mengembalikan Task. Karena ini adalah antarmuka, jangan gunakan async kata kunci. Contohnya:

public interface IClient
{
    Task ClientMethod();
}

Note

Akhiran Async tidak dilucuti dari nama metode. Kecuali metode klien Anda didefinisikan dengan .on('MyMethodAsync'), Anda tidak boleh menggunakan MyMethodAsync sebagai nama.

Mengubah nama metode hub

Secara default, nama metode hub server adalah nama metode .NET. Namun, Anda dapat menggunakan atribut HubMethodName untuk mengubah default ini dan menentukan nama untuk metode secara manual. Klien harus menggunakan nama ini, alih-alih nama metode .NET, saat memanggil metode:

[HubMethodName("SendMessageToUser")]
public Task DirectMessage(string user, string message)
{
    return Clients.User(user).SendAsync("ReceiveMessage", user, message);
}

Menangani peristiwa untuk koneksi

SignalR HUBS API menyediakan OnConnectedAsync metode virtual dan OnDisconnectedAsync untuk mengelola dan melacak koneksi. Ambil alih OnConnectedAsync metode virtual untuk melakukan tindakan saat klien terhubung ke Hub, seperti menambahkannya ke grup:

public override async Task OnConnectedAsync()
{
    await Groups.AddToGroupAsync(Context.ConnectionId, "SignalR Users");
    await base.OnConnectedAsync();
}

Ambil alih OnDisconnectedAsync metode virtual untuk melakukan tindakan saat klien terputus. Jika klien memutuskan sambungan dengan sengaja (dengan memanggil connection.stop(), misalnya), exception parameternya adalah null. Namun, jika klien terputus karena kesalahan (seperti kegagalan jaringan), exception parameter akan berisi pengecualian yang menjelaskan kegagalan:

public override async Task OnDisconnectedAsync(Exception exception)
{
    await Clients.Group("SignalR Users").SendAsync("ReceiveMessage", "I", "disconnect");
    await base.OnDisconnectedAsync(exception);
}

RemoveFromGroupAsync tidak perlu dipanggil dalam OnDisconnectedAsync, secara otomatis ditangani untuk Anda.

Warning

Peringatan keamanan: Mempublikasikan ConnectionId bisa berakibat pada peniruan jahat jika SignalR server atau versi klien adalah ASP.NET Core 2.2 atau yang lebih rendah.

Menangani kesalahan

Pengecualian yang terjadi dalam metode hub Anda dikirimkan ke klien yang memanggil metode ini. Pada klien JavaScript, invoke metode mengembalikan JavaScript Promise. Ketika klien menerima kesalahan dengan handler yang melekat pada promise menggunakan catch, handler tersebut dipanggil dan diteruskan sebagai objek JavaScript Error.

connection.invoke("SendMessage", user, message).catch(err => console.error(err));

Jika Hub Anda mengeluarkan pengecualian, koneksi tidak ditutup. Secara default, SignalR mengembalikan pesan kesalahan umum kepada klien. Contohnya:

Microsoft.AspNetCore.SignalR.HubException: An unexpected error occurred invoking 'MethodName' on the server.

Pengecualian tak terduga sering berisi informasi sensitif, seperti nama server database dalam pengecualian yang dipicu ketika koneksi database gagal. SignalR tidak mengekspos pesan kesalahan terperinci ini secara default sebagai ukuran keamanan. Untuk informasi selengkapnya tentang mengapa detail pengecualian ditekan, lihat Pertimbangan keamanan di ASP.NET Core SignalR.

Jika Anda memiliki kondisi luar biasa yang ingin Anda sebarkan ke klien, Anda dapat menggunakan kelas .HubException Jika Anda melempar HubException dari metode hub Anda, SignalRakan mengirim seluruh pesan ke klien, tidak dimodifikasi:

public Task ThrowException()
{
    throw new HubException("This error will be sent to the client!");
}

Note

SignalR hanya mengirim Message properti pengecualian ke klien. Jejak tumpukan dan properti lainnya pada pengecualian tidak dapat diakses oleh klien.

Sumber daya tambahan

Oleh Rachel Appel dan Kevin Griffin

Melihat atau mengunduh kode sampel (cara mengunduh)

Apa itu SignalR hub

SignalR HUBS API memungkinkan klien yang terhubung untuk memanggil metode di server, memfasilitasi komunikasi real-time. Server mendefinisikan metode yang dipanggil oleh klien, dan klien menentukan metode yang dipanggil oleh server. SignalR juga memungkinkan komunikasi klien-ke-klien tidak langsung, selalu dimediasi oleh SignalR Hub, memungkinkan pesan dikirim antara klien individu, grup, atau ke semua klien yang terhubung. SignalR mengurus semua yang diperlukan untuk memungkinkan komunikasi klien-ke-server dan server-ke-klien secara real-time.

Mengonfigurasi SignalR hub

Middleware SignalR memerlukan beberapa layanan, yang dikonfigurasi dengan memanggil AddSignalR:

services.AddSignalR();

Saat menambahkan SignalR fungsionalitas ke dalam aplikasi ASP.NET Core, siapkan rute SignalR dengan memanggil UseSignalR di dalam metode Startup.Configure.

app.UseSignalR(route =>
{
    route.MapHub<ChatHub>("/chathub");
});

Membuat dan menggunakan hub

Buat hub dengan mendeklarasikan kelas yang mewarisi dari Hub, dan menambahkan metode publik ke dalamnya. Klien dapat memanggil metode yang didefinisikan sebagai public:

public class ChatHub : Hub
{
    public Task SendMessage(string user, string message)
    {
        return Clients.All.SendAsync("ReceiveMessage", user, message);
    }
}

Anda dapat menentukan jenis pengembalian dan parameter, termasuk jenis dan array kompleks, seperti yang Anda lakukan dalam metode C# apa pun. SignalR menangani serialisasi dan deserialisasi objek dan array kompleks dalam parameter Anda dan mengembalikan nilai.

Note

Hub bersifat sementara:

  • Jangan menyimpan state dalam properti pada kelas hub. Setiap panggilan metode hub dijalankan pada instans hub baru.
  • Jangan membuat instans hub secara langsung melalui injeksi dependensi. Untuk mengirim pesan ke klien dari tempat lain di aplikasi Anda, gunakan IHubContext.
  • Gunakan await saat memanggil metode asinkron yang bergantung pada hub tetap hidup. Misalnya, metode seperti Clients.All.SendAsync(...) dapat gagal jika dipanggil tanpa await dan metode hub selesai sebelum SendAsync selesai.

Objek Konteks

Kelas Hub memiliki Context properti yang berisi properti berikut dengan informasi tentang koneksi:

Property Description
ConnectionId Mendapatkan ID unik untuk koneksi, yang ditetapkan oleh SignalR. Ada satu ID koneksi untuk setiap koneksi.
UserIdentifier Mendapatkan pengidentifikasi pengguna. Secara default, SignalR menggunakan ClaimTypes.NameIdentifier dari yang ClaimsPrincipal terkait dengan koneksi sebagai pengidentifikasi pengguna.
User Mendapatkan ClaimsPrincipal yang terkait dengan pengguna saat ini.
Items Mendapatkan kumpulan kunci/nilai yang dapat digunakan untuk berbagi data dalam cakupan koneksi ini. Data dapat disimpan dalam kumpulan ini dan akan tetap ada untuk koneksi selama berbagai pemanggilan metode hub.
Features Mendapatkan kumpulan fitur yang tersedia pada koneksi. Untuk saat ini, koleksi ini tidak diperlukan dalam sebagian besar skenario, sehingga belum didokumenkan secara rinci.
ConnectionAborted Mendapatkan sebuah CancellationToken yang memberi tahu ketika koneksi dibatalkan.

Hub.Context juga berisi metode berikut:

Method Description
GetHttpContext Mengembalikan HttpContext untuk koneksi, atau null jika koneksi tidak terkait dengan permintaan HTTP. Untuk koneksi HTTP, Anda dapat menggunakan metode ini untuk mendapatkan informasi seperti header HTTP dan string kueri.
Abort Membatalkan koneksi.

Objek Klien (Clients object)

Kelas Hub memiliki Clients properti yang berisi properti berikut untuk komunikasi antara server dan klien:

Property Description
All Menjalankan metode pada semua klien yang terhubung
Caller Memanggil metode pada klien yang memanggil metode hub
Others Memanggil metode pada semua klien yang terhubung kecuali klien yang memanggil metode

Hub.Clients juga berisi metode berikut:

Method Description
AllExcept Memanggil metode pada semua klien yang terhubung kecuali untuk koneksi yang ditentukan
Client Memanggil metode pada klien terhubung tertentu
Clients Memanggil metode pada klien tertentu yang terhubung
Group Memanggil metode pada semua koneksi dalam grup yang ditentukan
GroupExcept Memanggil metode pada semua koneksi dalam grup yang ditentukan, kecuali koneksi yang ditentukan
Groups Memanggil metode pada beberapa grup koneksi
OthersInGroup Memanggil metode pada sekelompok koneksi, tidak termasuk klien yang memanggil metode hub
User Memanggil metode pada semua koneksi yang terkait dengan pengguna tertentu
Users Memanggil metode pada semua koneksi yang terkait dengan pengguna yang ditentukan

Setiap properti atau metode dalam tabel sebelumnya mengembalikan objek dengan SendAsync metode . Metode SendAsync memungkinkan Anda memberikan nama dan parameter dari metode klien yang akan dipanggil.

Mengirim pesan ke klien

Untuk melakukan panggilan ke klien tertentu, gunakan properti Clients objek. Dalam contoh berikut, ada tiga metode Hub:

  • SendMessage mengirim pesan ke semua klien yang terhubung, menggunakan Clients.All.
  • SendMessageToCaller mengirim pesan kembali ke pemanggil, menggunakan Clients.Caller.
  • SendMessageToGroup mengirim pesan ke semua klien dalam SignalR Users grup.
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);
}

Hub dengan tiped kuat

Kelemahan penggunaannya SendAsync adalah mengandalkan string ajaib untuk menentukan metode klien yang akan dipanggil. Ini membuat kode terbuka untuk kesalahan runtime jika nama metode salah eja atau hilang dari klien.

Alternatif untuk menggunakan SendAsync adalah mengetik Hub dengan kuat dengan Hub<T>. Dalam contoh berikut, ChatHub metode klien telah diekstraksi ke antarmuka yang disebut IChatClient.

public interface IChatClient
{
    Task ReceiveMessage(string user, string message);
}

Antarmuka ini dapat digunakan untuk merefaktor contoh sebelumnya 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);
        }
}

Menggunakan Hub<IChatClient> mengaktifkan pemeriksaan waktu kompilasi metode klien. Ini mencegah masalah yang disebabkan oleh penggunaan string ajaib, karena Hub<T> hanya dapat menyediakan akses ke metode yang ditentukan dalam antarmuka.

Menggunakan Hub<T> yang bertipe kuat menonaktifkan kemampuan untuk menggunakan SendAsync. Metode apa pun yang ditentukan pada antarmuka masih dapat didefinisikan sebagai asinkron. Bahkan, masing-masing metode ini harus mengembalikan Task. Karena ini adalah antarmuka, jangan gunakan async kata kunci. Contohnya:

public interface IClient
{
    Task ClientMethod();
}

Note

Akhiran Async tidak dilucuti dari nama metode. Kecuali metode klien Anda didefinisikan dengan .on('MyMethodAsync'), Anda tidak boleh menggunakan MyMethodAsync sebagai nama.

Mengubah nama metode hub

Secara default, nama metode hub server adalah nama metode .NET. Namun, Anda dapat menggunakan atribut HubMethodName untuk mengubah default ini dan menentukan nama untuk metode secara manual. Klien harus menggunakan nama ini, alih-alih nama metode .NET, saat memanggil metode:

[HubMethodName("SendMessageToUser")]
public Task DirectMessage(string user, string message)
{
    return Clients.User(user).SendAsync("ReceiveMessage", user, message);
}

Menangani peristiwa untuk koneksi

SignalR HUBS API menyediakan OnConnectedAsync metode virtual dan OnDisconnectedAsync untuk mengelola dan melacak koneksi. Ambil alih OnConnectedAsync metode virtual untuk melakukan tindakan saat klien terhubung ke Hub, seperti menambahkannya ke grup:

public override async Task OnConnectedAsync()
{
    await Groups.AddToGroupAsync(Context.ConnectionId, "SignalR Users");
    await base.OnConnectedAsync();
}

Ambil alih OnDisconnectedAsync metode virtual untuk melakukan tindakan saat klien terputus. Jika klien memutuskan sambungan dengan sengaja (dengan memanggil connection.stop(), misalnya), exception parameternya adalah null. Namun, jika klien terputus karena kesalahan (seperti kegagalan jaringan), exception parameter akan berisi pengecualian yang menjelaskan kegagalan:

public override async Task OnDisconnectedAsync(Exception exception)
{
    await Clients.Group("SignalR Users").SendAsync("ReceiveMessage", "I", "disconnect");
    await base.OnDisconnectedAsync(exception);
}

RemoveFromGroupAsync tidak perlu dipanggil dalam OnDisconnectedAsync, secara otomatis ditangani untuk Anda.

Warning

Peringatan keamanan: Mempublikasikan ConnectionId bisa berakibat pada peniruan jahat jika SignalR server atau versi klien adalah ASP.NET Core 2.2 atau yang lebih rendah.

Menangani kesalahan

Pengecualian yang terjadi dalam metode hub Anda dikirimkan ke klien yang memanggil metode ini. Pada klien JavaScript, invoke metode mengembalikan JavaScript Promise. Ketika klien menerima kesalahan dengan handler yang melekat pada promise menggunakan catch, handler tersebut dipanggil dan diteruskan sebagai objek JavaScript Error.

connection.invoke("SendMessage", user, message).catch(err => console.error(err));

Jika Hub Anda mengeluarkan pengecualian, koneksi tidak ditutup. Secara default, SignalR mengembalikan pesan kesalahan umum kepada klien. Contohnya:

Microsoft.AspNetCore.SignalR.HubException: An unexpected error occurred invoking 'MethodName' on the server.

Pengecualian tak terduga sering berisi informasi sensitif, seperti nama server database dalam pengecualian yang dipicu ketika koneksi database gagal. SignalR tidak mengekspos pesan kesalahan terperinci ini secara default sebagai ukuran keamanan. Untuk informasi selengkapnya tentang mengapa detail pengecualian ditekan, lihat Pertimbangan keamanan di ASP.NET Core SignalR.

Jika Anda memiliki kondisi luar biasa yang ingin Anda sebarkan ke klien, Anda dapat menggunakan kelas .HubException Jika Anda melempar HubException dari metode hub Anda, SignalRakan mengirim seluruh pesan ke klien, tidak dimodifikasi:

public Task ThrowException()
{
    throw new HubException("This error will be sent to the client!");
}

Note

SignalR hanya mengirim Message properti pengecualian ke klien. Jejak tumpukan dan properti lainnya pada pengecualian tidak dapat diakses oleh klien.

Sumber daya tambahan