Bagikan melalui


SignalR Pertimbangan desain API

Oleh Andrew Stanton-Perawat

Artikel ini menyediakan panduan untuk membangun SignalRAPI berbasis.

Menggunakan parameter objek kustom untuk memastikan kompatibilitas mundur

Menambahkan parameter ke SignalR metode hub (baik pada klien atau server) adalah perubahan yang melanggar. Ini berarti klien/server yang lebih lama akan mendapatkan kesalahan ketika mereka mencoba memanggil metode tanpa jumlah parameter yang sesuai. Namun, menambahkan properti ke parameter objek kustom bukanlah perubahan yang melanggar. Ini dapat digunakan untuk merancang API yang kompatibel yang tahan terhadap perubahan pada klien atau server.

Misalnya, pertimbangkan API sisi server seperti berikut ini:

public int GetTotalLength(string param1)
{
    return param1.Length;
}

Klien JavaScript memanggil metode ini menggunakan invoke sebagai berikut:

connection.invoke("GetTotalLength", "value1");

Jika nanti Anda menambahkan parameter kedua ke metode server, klien yang lebih lama tidak akan memberikan nilai parameter ini. Contohnya:

public int GetTotalLength(string param1, string param2)
{
    return param1.Length + param2.Length;
}

Ketika klien lama mencoba memanggil metode ini, ia akan mendapatkan kesalahan seperti ini:

Microsoft.AspNetCore.SignalR.HubException: Failed to invoke 'GetTotalLength' due to an error on the server.

Di server, Anda akan melihat pesan log seperti ini:

System.IO.InvalidDataException: Invocation provides 1 argument(s) but target expects 2.

Klien lama hanya mengirim satu parameter, tetapi API server yang lebih baru memerlukan dua parameter. Menggunakan objek kustom sebagai parameter memberi Anda lebih banyak fleksibilitas. Mari kita desain ulang API asli untuk menggunakan objek kustom:

public class TotalLengthRequest
{
    public string Param1 { get; set; }
}

public int GetTotalLength(TotalLengthRequest req)
{
    return req.Param1.Length;
}

Sekarang, klien menggunakan objek untuk memanggil metode :

connection.invoke("GetTotalLength", { param1: "value1" });

Alih-alih menambahkan parameter, tambahkan properti ke TotalLengthRequest objek:

public class TotalLengthRequest
{
    public string Param1 { get; set; }
    public string Param2 { get; set; }
}

public int GetTotalLength(TotalLengthRequest req)
{
    var length = req.Param1.Length;
    if (req.Param2 != null)
    {
        length += req.Param2.Length;
    }
    return length;
}

Ketika klien lama mengirim satu parameter, properti tambahan Param2 akan dibiarkan null. Anda dapat mendeteksi pesan yang dikirim oleh klien lama dengan memeriksa Param2null dan menerapkan nilai default. Klien baru dapat mengirim kedua parameter.

connection.invoke("GetTotalLength", { param1: "value1", param2: "value2" });

Teknik yang sama berfungsi untuk metode yang ditentukan pada klien. Anda dapat mengirim objek kustom dari sisi server:

public async Task Broadcast(string message)
{
    await Clients.All.SendAsync("ReceiveMessage", new
    {
        Message = message
    });
}

Di sisi klien, Anda mengakses Message properti daripada menggunakan parameter:

connection.on("ReceiveMessage", (req) => {
    appendMessageToChatWindow(req.message);
});

Jika nanti Anda memutuskan untuk menambahkan pengirim pesan ke payload, tambahkan properti ke objek :

public async Task Broadcast(string message)
{
    await Clients.All.SendAsync("ReceiveMessage", new
    {
        Sender = Context.User.Identity.Name,
        Message = message
    });
}

Klien yang lebih lama tidak akan mengharapkan nilainya Sender , sehingga mereka akan mengabaikannya. Klien baru dapat menerimanya dengan memperbarui untuk membaca properti baru:

connection.on("ReceiveMessage", (req) => {
    let message = req.message;
    if (req.sender) {
        message = req.sender + ": " + message;
    }
    appendMessageToChatWindow(message);
});

Dalam hal ini, klien baru juga toleran terhadap server lama yang tidak memberikan nilai.Sender Karena server lama tidak akan memberikan Sender nilai, klien memeriksa untuk melihat apakah ada sebelum mengaksesnya.

Sumber Daya Tambahan: