ASP.NET Core SignalR (七):考虑设计向后兼容的SignalR API

摘要:
这可用于设计兼容API,以允许客户端或服务器端的更改。让我们重新设计服务器API以使用自定义对象:publicclassTotalLengthRequest{publicstringParam1{get;set;}}publicasyncTaskGetTotalLength{returnreq.Param1.Length;}现在,客户端使用一个对象来调用此方法:连接调用;我们不添加参数,而是向TotalLengthRequest对象添加一个属性:publicclassTotalLenghRequest{publicstringParam1{get;set;}publicstringParam2{get;set;}}PublicsyncTaskGetTotalLength{varlength=req.Param1.Length;如果(req.Param2!),新客户端可以发送两个参数:connection。援引对于客户端上定义的方法,相同的方法可以正常工作。publicasyncTaskBroadcast{awaitClients.All.SendAsync;}旧客户端不期望Sender值,因此忽略它。
此为系列文章,对MSDN ASP.NET Core SignalR 的官方文档进行系统学习与翻译。其中或许会添加本人对 ASP.NET Core 的浅显理解。

使用自定义参数对象来确保向后兼容

        向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 值,客户端会在访问它之前查看其是否存在。

免责声明:文章转载自《ASP.NET Core SignalR (七):考虑设计向后兼容的SignalR API》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇Windows 8.1系统及实用软件企业级虚拟化实战之KVM——虚拟机迁移下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

DELPHI字符串、数组操作函数(转)

对字符串及数组的操作,是每个程序员必须要掌握的。熟练的使用Delphi的这些函数,在编程时能更加得心应手。   1.Copy   功能说明:该函数用于从字符串中复制指定范围中的字符。该函数有3个参数。第一个参数是数据源(即被复制的字符串),第二个参数是从字符串某一处开始复制,第三个参数是要复制字符串的长度(   即个数)。最后函数返回一个新的字符串(即是我...

C# Dictionary通过value获取对应的key值[转发]

1:最直白的循环遍历方法,可以分为遍历key--value键值对以及所有的key两种表现形式 2:用Linq的方式去查询(当然了这里要添加对应的命名空间 using System.Linq)  如下为一个十分简单的代码示例: private void GetDicKeyByValue() { Dictionary...

将MP3文件嵌入到exe中并播放

需要编写一个exe文件,而其中嵌入了一段我设计好的音乐,打开exe后音乐自动播放。最重要的是除了 exe 文件外不能有额外的附加文件,将这个exe拷到其他(安装有framework的)电脑上,需要能正常运行。 1.资源嵌入 这个比较简单,vs2008 提供了非常方便的方法,新增一个项目后,打开 Properties 文件夹下的 Resources.res...

带中文的字符串截取

最近在页面展示的时候遇到这样的场景,文字有可能超长,却又不允许换行。 当然,可以用高超的css来搞定。但如果你想要让多余的文字用“...”来代替,并且要兼容很多浏览器,这种时候用css也会很头疼吧。 1.C#对中文字符串的截取 与英文字符相比,我们把中文字符按两个占位来计算,对于带中文的字符串截取,要面临两个问题: 1.无法截取半个中文字符; 2.对于除...

Spring中使用RedisTemplate操作Redis(spring-data-redis)

RedisTemplate如何检查一个key是否存在? return getRedisTemplate().hasKey(key); 由一个问题,复习了一下redis 抄自: https://www.jianshu.com/p/7bf5dc61ca06大部分都试了一遍 Redis 数据结构简介 Redis可以存储键与5种不同数据结构类型之间的映射,这5种数...

es-09-spark集成

es和spark的集成比较简单, 直接使用内部封装的一些方法即可 版本设置说明: https://www.elastic.co/guide/en/elasticsearch/hadoop/current/requirements.html maven依赖说明: https://www.elastic.co/guide/en/elasticsearch/ha...