Menggunakan hub untuk SignalR ASP.NET Core

Oleh Rachel Appel dan Kevin Griffin

SignalR HUBS API memungkinkan klien yang terhubung untuk memanggil metode di server. Server mendefinisikan metode yang dipanggil dari klien dan klien menentukan metode yang dipanggil dari server. 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, hubungi AddSignalR di Program.cs:

var builder = WebApplication.CreateBuilder(args);

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

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

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

app.Run();

Catatan

ASP.NET rakitan sisi server Core SignalR sekarang diinstal dengan .NET Core SDK. Lihat SignalR rakitan dalam kerangka kerja bersama untuk informasi selengkapnya.

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

Catatan

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:

Properti Deskripsi
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 yang ClaimsPrincipal 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 akan bertahan untuk koneksi di 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 CancellationToken Mendapatkan yang memberi tahu ketika koneksi dibatalkan.

Hub.Context juga berisi metode berikut:

Metode Deskripsi
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

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

Properti Deskripsi
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

Hub.Clients juga berisi metode berikut:

Metode Deskripsi
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 ini SendAsync menerima nama metode klien untuk memanggil dan parameter apa pun.

Objek yang Client dikembalikan oleh metode dan Caller juga berisi InvokeAsync metode, 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 yang sangat ditik

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 ChatHub contoh sebelumnya untuk diketik dengan 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. Ini mencegah masalah yang disebabkan oleh penggunaan string, karena Hub<T> hanya dapat menyediakan akses ke metode yang ditentukan dalam antarmuka. Menggunakan tipe yang sangat Hub<T> kuat menonaktifkan kemampuan untuk menggunakan SendAsync.

Catatan

Akhiran Async tidak dilucuti 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(...) instans :IHubContext<T>

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

Hub yang sangat di ketik 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);
    }
}

Catatan

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.

Dukungan layanan utama dalam Injeksi Dependensi

Layanan utama mengacu pada mekanisme untuk mendaftarkan dan mengambil layanan Dependency Injection (DI) menggunakan kunci. Layanan dikaitkan dengan kunci dengan memanggil AddKeyedSingleton (atau AddKeyedScoped atau AddKeyedTransient) untuk mendaftarkannya. Akses layanan terdaftar dengan menentukan kunci dengan [FromKeyedServices] atribut . 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"));
    }
}

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 , secara otomatis ditangani OnDisconnectedAsyncuntuk Anda.

Menangani kesalahan

Pengecualian yang dilemparkan dalam metode hub dikirim ke klien yang memanggil metode . Pada klien JavaScript, invoke metode mengembalikan JavaScript Promise. Klien dapat melampirkan catch handler ke janji yang dikembalikan atau digunakan trycatch/dengan async/await untuk menangani pengecualian:

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

Koneksi tidak ditutup saat hub melemparkan 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!");

Catatan

SignalR hanya mengirim Message properti pengecualian ke klien. Jejak tumpukan dan properti lain pada pengecualian tidak tersedia untuk klien.

Sumber daya tambahan

Oleh Rachel Appel dan Kevin Griffin

SignalR HUBS API memungkinkan klien yang terhubung untuk memanggil metode di server. Server mendefinisikan metode yang dipanggil dari klien dan klien menentukan metode yang dipanggil dari server. 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, hubungi AddSignalR di Program.cs:

var builder = WebApplication.CreateBuilder(args);

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

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

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

app.Run();

Catatan

ASP.NET rakitan sisi server Core SignalR sekarang diinstal dengan .NET Core SDK. Lihat SignalR rakitan dalam kerangka kerja bersama untuk informasi selengkapnya.

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

Catatan

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:

Properti Deskripsi
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 yang ClaimsPrincipal 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 akan bertahan untuk koneksi di 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 CancellationToken Mendapatkan yang memberi tahu ketika koneksi dibatalkan.

Hub.Context juga berisi metode berikut:

Metode Deskripsi
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

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

Properti Deskripsi
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

Hub.Clients juga berisi metode berikut:

Metode Deskripsi
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 ini SendAsync menerima nama metode klien untuk memanggil dan parameter apa pun.

Objek yang Client dikembalikan oleh metode dan Caller juga berisi InvokeAsync metode, 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 yang sangat ditik

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 ChatHub contoh sebelumnya untuk diketik dengan 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. Ini mencegah masalah yang disebabkan oleh penggunaan string, karena Hub<T> hanya dapat menyediakan akses ke metode yang ditentukan dalam antarmuka. Menggunakan tipe yang sangat Hub<T> kuat menonaktifkan kemampuan untuk menggunakan SendAsync.

Catatan

Akhiran Async tidak dilucuti 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(...) instans :IHubContext<T>

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

Hub yang sangat di ketik 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);
    }
}

Catatan

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 , secara otomatis ditangani OnDisconnectedAsyncuntuk Anda.

Menangani kesalahan

Pengecualian yang dilemparkan dalam metode hub dikirim ke klien yang memanggil metode . Pada klien JavaScript, invoke metode mengembalikan JavaScript Promise. Klien dapat melampirkan catch handler ke janji yang dikembalikan atau digunakan trycatch/dengan async/await untuk menangani pengecualian:

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

Koneksi tidak ditutup saat hub melemparkan 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!");

Catatan

SignalR hanya mengirim Message properti pengecualian ke klien. Jejak tumpukan dan properti lain pada pengecualian tidak tersedia untuk klien.

Sumber daya tambahan

Oleh Rachel Appel dan Kevin Griffin

SignalR HUBS API memungkinkan klien yang terhubung untuk memanggil metode di server. Server mendefinisikan metode yang dipanggil dari klien dan klien menentukan metode yang dipanggil dari server. 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, hubungi AddSignalR di Program.cs:

var builder = WebApplication.CreateBuilder(args);

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

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

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

app.Run();

Catatan

ASP.NET rakitan sisi server Core SignalR sekarang diinstal dengan .NET Core SDK. Lihat SignalR rakitan dalam kerangka kerja bersama untuk informasi selengkapnya.

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

Catatan

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:

Properti Deskripsi
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 yang ClaimsPrincipal 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 akan bertahan untuk koneksi di 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 CancellationToken Mendapatkan yang memberi tahu ketika koneksi dibatalkan.

Hub.Context juga berisi metode berikut:

Metode Deskripsi
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

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

Properti Deskripsi
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

Hub.Clients juga berisi metode berikut:

Metode Deskripsi
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 ini SendAsync menerima nama metode klien untuk memanggil dan 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 yang sangat ditik

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 ChatHub contoh sebelumnya untuk diketik dengan 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. Ini mencegah masalah yang disebabkan oleh penggunaan string, karena Hub<T> hanya dapat menyediakan akses ke metode yang ditentukan dalam antarmuka. Menggunakan tipe yang sangat Hub<T> kuat menonaktifkan kemampuan untuk menggunakan SendAsync.

Catatan

Akhiran Async tidak dilucuti 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 , secara otomatis ditangani OnDisconnectedAsyncuntuk Anda.

Menangani kesalahan

Pengecualian yang dilemparkan dalam metode hub dikirim ke klien yang memanggil metode . Pada klien JavaScript, invoke metode mengembalikan JavaScript Promise. Klien dapat melampirkan catch handler ke janji yang dikembalikan atau digunakan trycatch/dengan async/await untuk menangani pengecualian:

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

Koneksi tidak ditutup saat hub melemparkan 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!");

Catatan

SignalR hanya mengirim Message properti pengecualian ke klien. Jejak tumpukan dan properti lain pada pengecualian tidak tersedia untuk klien.

Sumber daya tambahan

Oleh Rachel Appel dan Kevin Griffin

Menampilkan atau mengunduh kode sampel (cara mengunduh)

Apa itu SignalR hub

SignalR Hubs API memungkinkan Anda memanggil metode pada klien yang terhubung dari server. Dalam kode server, Anda menentukan metode yang dipanggil oleh klien. Dalam kode klien, Anda menentukan metode yang dipanggil dari server. SignalR mengurus segala sesuatu di belakang layar yang memungkinkan komunikasi klien-ke-server dan server-ke-klien 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 panggilan Startup.Configure balik metode UseEndpoints :

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

Catatan

ASP.NET rakitan sisi server Core SignalR sekarang diinstal dengan .NET Core SDK. Lihat SignalR rakitan dalam kerangka kerja bersama untuk informasi selengkapnya.

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.

Catatan

Hub bersifat sementara:

  • Jangan menyimpan status dalam properti di 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:

Properti Deskripsi
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 yang ClaimsPrincipal 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 akan bertahan untuk koneksi di 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 CancellationToken Mendapatkan yang memberi tahu ketika koneksi dibatalkan.

Hub.Context juga berisi metode berikut:

Metode Deskripsi
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

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

Properti Deskripsi
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

Hub.Clients juga berisi metode berikut:

Metode Deskripsi
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 ini SendAsync memungkinkan Anda untuk memberikan nama dan parameter metode klien untuk 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 yang sangat ditik

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 tipe yang sangat Hub<T> 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. Contoh:

public interface IClient
{
    Task ClientMethod();
}

Catatan

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 , secara otomatis ditangani OnDisconnectedAsyncuntuk Anda.

Peringatan

Peringatan keamanan: Mengekspos ConnectionId dapat menyebabkan peniruan berbahaya jika SignalR server atau versi klien ASP.NET Core 2.2 atau yang lebih lama.

Menangani kesalahan

Pengecualian yang dilemparkan dalam metode hub Anda dikirim ke klien yang memanggil metode . Pada klien JavaScript, invoke metode mengembalikan JavaScript Promise. Ketika klien menerima kesalahan dengan handler yang melekat pada janji menggunakan catch, klien dipanggil dan diteruskan sebagai objek JavaScript Error :

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

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

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

Catatan

SignalR hanya mengirim Message properti pengecualian ke klien. Jejak tumpukan dan properti lain pada pengecualian tidak tersedia untuk klien.

Sumber daya tambahan

Oleh Rachel Appel dan Kevin Griffin

Menampilkan atau mengunduh kode sampel (cara mengunduh)

Apa itu SignalR hub

SignalR Hubs API memungkinkan Anda memanggil metode pada klien yang terhubung dari server. Dalam kode server, Anda menentukan metode yang dipanggil oleh klien. Dalam kode klien, Anda menentukan metode yang dipanggil dari server. SignalR mengurus segala sesuatu di belakang layar yang memungkinkan komunikasi klien-ke-server dan server-ke-klien 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 UseSignalR dalam Startup.Configure metode :

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.

Catatan

Hub bersifat sementara:

  • Jangan menyimpan status dalam properti di 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:

Properti Deskripsi
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 yang ClaimsPrincipal 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 akan bertahan untuk koneksi di 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 CancellationToken Mendapatkan yang memberi tahu ketika koneksi dibatalkan.

Hub.Context juga berisi metode berikut:

Metode Deskripsi
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

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

Properti Deskripsi
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

Hub.Clients juga berisi metode berikut:

Metode Deskripsi
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 ini SendAsync memungkinkan Anda untuk memberikan nama dan parameter metode klien untuk 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 yang sangat ditik

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 tipe yang sangat Hub<T> 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. Contoh:

public interface IClient
{
    Task ClientMethod();
}

Catatan

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 , secara otomatis ditangani OnDisconnectedAsyncuntuk Anda.

Peringatan

Peringatan keamanan: Mengekspos ConnectionId dapat menyebabkan peniruan berbahaya jika SignalR server atau versi klien ASP.NET Core 2.2 atau yang lebih lama.

Menangani kesalahan

Pengecualian yang dilemparkan dalam metode hub Anda dikirim ke klien yang memanggil metode . Pada klien JavaScript, invoke metode mengembalikan JavaScript Promise. Ketika klien menerima kesalahan dengan handler yang melekat pada janji menggunakan catch, klien dipanggil dan diteruskan sebagai objek JavaScript Error :

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

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

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

Catatan

SignalR hanya mengirim Message properti pengecualian ke klien. Jejak tumpukan dan properti lain pada pengecualian tidak tersedia untuk klien.

Sumber daya tambahan