本文指导如何生成基于 SignalR 的 API。
使用自定义对象参数确保向后兼容性
将参数添加到 SignalR 中心方法(在客户端或服务器上)是一项中断性变更。 这意味着,较旧的客户端/服务器在尝试调用没有适当数量参数的方法时会出错。 但是,向自定义对象参数添加属性不是一项中断性变更。 这可用于设计兼容的 API,以适应客户端或服务器上的更改。
以如下所示的服务器端 API 为例:
public int GetTotalLength(string param1)
return param1.Length;
JavaScript 客户端使用 invoke
调用此方法,如下所示:
connection.invoke("GetTotalLength", "value1");
如果稍后将第二个参数添加到服务器方法,旧客户端不会提供此参数值。 例如:
public int 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 int 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 int 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
值,因此客户端在访问它之前会检查它是否存在。
共享框架中的 SignalR 程序集