本文提供了用于构建基于 SignalR 的 Api 的指南。
将参数添加到 SignalR 集线器方法 (在客户端或服务器) 是重大更改。 这意味着较旧的客户端/服务器会在尝试调用不带适当数量的参数的方法时出现错误。 但是,将属性添加到自定义对象参数是不一项重大更改。 这可以用于设计兼容的 Api 时可复原的客户端或服务器上的更改。
例如,考虑如下所示的服务器端 API:
public async Task<string> GetTotalLength(string param1) { return param1.Length; }
JavaScript 客户端调用此方法使用invoke
,如下所示:
connection.invoke("GetTotalLength", "value1");
如果以后服务器方法中添加第二个参数,较旧的客户端不会提供此参数值。 例如:
public async Task<string> GetTotalLength(string param1, string param2) { return param1.Length + param2.Length; }
当旧客户端尝试调用此方法时,它会收到如下错误:
Microsoft.AspNetCore.SignalR.HubException: Failed to invoke 'GetTotalLength' due to an error on the server.
在服务器上,将看到一条日志消息如下:
System.IO.InvalidDataException: Invocation provides 1 argument(s) but target expects 2.
旧客户端仅发送一个参数,但较新版本的服务器 API 所需的两个参数。 使用自定义对象作为参数提供了更大的灵活性。 让我们重新设计要使用自定义对象的原始 API:
public class TotalLengthRequest { public string Param1 { get; set; } } public async Task GetTotalLength(TotalLengthRequest req) { return req.Param1.Length; }
现在,客户端使用对象调用方法:
connection.invoke("GetTotalLength", { param1: "value1" });
无需添加参数,将属性添加到TotalLengthRequest
对象:
public class TotalLengthRequest { public string Param1 { get; set; } public string Param2 { get; set; } } public async Task GetTotalLength(TotalLengthRequest req) { var length = req.Param1.Length; if (req.Param2 != null) { length += req.Param2.Length; } return length; }
当旧客户端发送一个参数,额外Param2
属性将保留null
。 你可以检测到通过检查由较旧的客户端发送的消息Param2
为null
并应用默认值。 新的客户端可以发送两个参数。
connection.invoke("GetTotalLength", { param1: "value1", param2: "value2" });
相同的方法适用于在客户端上定义的方法。 可以从服务器端发送自定义对象:
public async Task Broadcast(string message) { await Clients.All.SendAsync("ReceiveMessage", new { Message = message }); }
在客户端上,访问Message
属性,而无需使用参数:
connection.on("ReceiveMessage", (req) => { appendMessageToChatWindow(req.message); });
如果你稍后决定要将消息的发件人添加到负载,请向对象添加属性:
public async Task Broadcast(string message) { await Clients.All.SendAsync("ReceiveMessage", new { Sender = Context.User.Identity.Name, Message = message }); }
较旧的客户端不应为Sender
值,因此将其忽略。 新的客户端可以通过接受更新,以读取新属性:
connection.on("ReceiveMessage", (req) => { let message = req.message; if (req.sender) { message = req.sender + ": " + message; } appendMessageToChatWindow(message); });
在这种情况下,新的客户端也是不提供的旧服务器的容错Sender
值。 由于旧的服务器不会提供Sender
值时,客户端检查以查看是否存在之前对其进行访问。