ASP.NET Core的实时库: SignalR简介及使用
大纲
本系列会分为2-3篇文章.
本文的内容:
SignalR
SignalR是一个.NET Core/.NET Framework的开源实时框架. SignalR的可使用Web Socket, Server Sent Events 和 Long Polling作为底层传输方式.
SignalR基于这三种技术构建, 抽象于它们之上, 它让你更好的关注业务问题而不是底层传输技术问题.
SignalR这个框架分服务器端和客户端, 服务器端支持ASP.NET Core 和 ASP.NET; 而客户端除了支持浏览器里的javascript以外, 也支持其它类型的客户端, 例如桌面应用.
回落机制
SignalR使用的三种底层传输技术分别是Web Socket, Server Sent Events 和 Long Polling.
其中Web Socket仅支持比较现代的浏览器, Web服务器也不能太老.
而Server Sent Events 情况可能好一点, 但是也存在同样的问题.
所以SignalR采用了回落机制, SignalR有能力去协商支持的传输类型.
Web Socket是最好的最有效的传输方式, 如果浏览器或Web服务器不支持它的话, 就会降级使用SSE, 实在不行就用Long Polling.
一旦建立连接, SignalR就会开始发送keep alive消息, 来检查连接是否还正常. 如果有问题, 就会抛出异常.
因为SignalR是抽象于三种传输方式的上层, 所以无论底层采用的哪种方式, SignalR的用法都是一样的.
SignalR默认采用这种回落机制来进行传输和连接.
但是也可以禁用回落机制, 只采用其中一种传输方式.
RPC
RPC (Remote Procedure Call). 它的优点就是可以像调用本地方法一样调用远程服务.
SignalR采用RPC范式来进行客户端与服务器端之间的通信.
SignalR利用底层传输来让服务器可以调用客户端的方法, 反之亦然, 这些方法可以带参数, 参数也可以是复杂对象, SignalR负责序列化和反序列化.
Hub
Hub是SignalR的一个组件, 它运行在ASP.NET Core应用里. 所以它是服务器端的一个类.
Hub使用RPC接受从客户端发来的消息, 也能把消息发送给客户端. 所以它就是一个通信用的Hub.
在ASP.NET Core里, 自己创建的Hub类需要继承于基类Hub.
在Hub类里面, 我们就可以调用所有客户端上的方法了. 同样客户端也可以调用Hub类里的方法.
这种Hub+RPC的方式还是非常适合实时场景的.
之前说过方法调用的时候可以传递复杂参数, SignalR可以将参数序列化和反序列化. 这些参数被序列化的格式叫做Hub 协议, 所以Hub协议就是一种用来序列化和反序列化的格式.
Hub协议的默认协议是JSON, 还支持另外一个协议是MessagePack. MessagePack是二进制格式的, 它比JSON更紧凑, 而且处理起来更简单快速, 因为它是二进制的.
此外, SignalR也可以扩展使用其它协议..
横向扩展
随着系统的运行, 有时您可能需要进行横向扩展. 就是应用运行在多个服务器上.
这时负载均衡器会保证每个进来的请求按照一定的逻辑分配到可能是不同的服务器上.
在使用Web Socket的时候, 没什么问题, 因为一旦Web Socket的连接建立, 就像在浏览器和那个服务器之间打开了隧道一样, 服务器是不会切换的.
但是如果使用Long Polling, 就可能有问题了, 因为使用Long Polling的情况下, 每次发送消息都是不同的请求, 而每次请求可能会到达不同的服务器. 不同的服务器可能不知道前一个服务器通信的内容, 这就会造成问题.
针对这个问题, 我们需要使用Sticky Sessions (粘性会话).
Sticky Sessions 貌似有很多中实现方式, 但是主要是下面要介绍的这种方式.
作为第一次请求的响应的一部分, 负载均衡器会在浏览器里面设置一个Cookie, 来表示使用过这个服务器. 在后续的请求里, 负载均衡器读取Cookie, 然后把请求分配给同一个服务器.
在ASP.NET Core 中使用SignalR
建立项目
使用空模板建立ASP.NET Core项目.
建立一个CountService:
建立一个CountHub, 继承于Hub:
配置SignalR
在Startup里注册SignalR:
如果需要的话可以在AddSignalR()这个方法里使用lambda表达式进行一些配置.
然后在管道里使用SignalR, 使用app.UseSignalR():
这里我已经建立了一个Hub, 叫做CountHub.
该方法的参数类型是Action<HubRouteBuilder>, 然后在这里配置hub的路由.
使用Hub
首先建立一个Controller, 并注入IHubContext<CountHub>:
接下来我们就可以使用IHubContext<CountHub>这个对象与客户端进行实时通信了.
下面建立一个POST Action, 客户端点击按钮之后来到这个Action, 在这里我们使用hub为所有的客户端发送一个消息:
这里, 我调用了所有客户端上的someFunc这个方法, 参数是一个对象.
但是使用这种IHubContext<Hub>的注入方式, 我们无法在它那取得Caller(调用该方法的客户端)这个属性.
Context
从Hub的Context属性, 我们可以获得用户的信息.
我们在CountHub里override父类的一个方法OnConnectedAsync():
如果有新的连接建立了, 这个方法就会被执行.
在Hub类里, 我们可以访问到Context属性. 从Context属性那, 我们可以获得一个常用的属性叫做ConnectionId. 这个ConnectionId就是连接到Hub的这个客户端的唯一标识.
使用ConnectionId, 我们就可以取得这个客户端, 并调用其方法, 如图中的Clients.Client(connectionId).xxx.
Hub的Clients属性表示客户端, 它有若干个方法可以选择客户端, 刚才的Client(connectionId)就是使用connectionId找到这一个客户端. 而AllExcept(connectionId)就是除了这个connectionId的客户端之外的所有客户端. 更多方法请查看文档.
SignalR还有Group分组的概念, 而且操作简单, 这里用到的是Hub的Groups属性. 向一个Group名添加第一个connectionId的时候, 分组就被建立. 移除分组内最后一个客户端的时候, 分组就被删除了. 使用Clients.Group("组名")可以调用组内客户端的方法.
授权和验证
SignalR会采用ASP.NET Core配置好的授权和验证体系.
用法和Controller差不多:
想要取得User对象, 需要使用Context.User, 它的类型是ClaimsPrinciple:
客户端
客户端需要安装signalr这个库. 可以使用npm安装 @aspnet/signalr
但是实际上只需要signalr.js一个文件即可.
客户端代码如下:
点击按钮后先执行Controller的POST方法, POST返回的是Accepted(1), 所以id是1.
使用singalR对象的HubConnectionBuilder来构建connection. 使用返回的connection对象, 我们可以用它的on方法来处理服务器端方法调用的响应. 响应方法的参数可以是简单类型也可以是复杂的对象.
使用connection.start()来打开连接, 使用catch()来捕获异常, 使用connection.stop() 关闭连接.
先运行一下看看效果:
可以看到使用Clients.All, 所有的客户端的方法都会被调用.
刚打开页面的时候, 我们就尝试建立连接, 从F12可以看到一个叫做negotiate的请求被发送了:
这个请求的body如下:
可以看到客户端选择了一个connectionId, 里面还有浏览器支持的传输方式.
服务器的响应:
响应也包含着connectionId, 以及服务器支持的传输方式. 这里三种都支持. 由于我没有指定传输方式, 所以SignalR选择了最好的方式: websocket.
而在我点击按钮后, Web Socket连接才被初始化:
如果需要手动指定传输方式, 请在withUrl()方法的第二个参数指定传输方式:
其它类型的客户端
.NET 客户端可以安装 Microsoft.AspNetCore.SignalR.Client 这个包来支持SignalR.
具体用法请查看官方文档, 语法和js的差不多.
MessagePack协议
需要安装 Microsoft.AspNetCore.SignalR.Protocols.MessagePack.
然后在Startup里面使用AddMessagePackProtocol()这个方法即可:
这样的话, 服务器端既支持JSON, 也支持MessagePack了.
另外.NET客户端也需要安装这个MessagePack包.
而js客户端需要安装 @aspnet/signalr-protocol-msgpack.
横向扩展 Scale-out
可以采用Redis, 需要安装 Microsoft.AspNetCore.SignalR.Redis. 这个包.
然后在Startup里面配置:
这个没试过, 请看官方文档.
SignalR就介绍这些....
ASP.NET Core的实时库: SignalR简介及使用的更多相关文章
- ASP.NET Core的实时库: SignalR -- 预备知识
大纲 本系列会分为2-3篇文章. 第一篇介绍SignalR的预备知识和原理 然后会介绍SignalR和如何在ASP.NET Core里使用SignalR. 本文的目录如下: 实时Web简述 Long ...
- 在ASP.NET CORE 2.0使用SignalR技术
一.前言 上次讲SignalR还是在<在ASP.NET Core下使用SignalR技术>文章中提到,ASP.NET Core 1.x.x 版本发布中并没有包含SignalR技术和开发计划 ...
- ASP.NET Core 1.1 Preview 1 简介(包含.NETCore 1.1升级公告)
ASP.NET Core 1.1 Preview 1于2016年10月25日发布.这个版本包括许多伟大的新功能以及许多错误修复和一般的增强. 要将现有项目更新到ASP.NET Core 1.1 Pre ...
- asp.net core 2.0集成signalr
在博客园也很多年了,一直未曾分享过什么东西,也没有写过博客,但自己也是汲取着博客园的知识成长的: 这两天想着不能这么无私,最近.NET CORE貌似挺流行的,闲来无事也自己搞了个asp.net cor ...
- Azure DevOps+Docker+Asp.NET Core 实现CI/CD(一 .简介与创建自己的代理池)
前言 本文主要是讲解如何使用Azure DevOps+Docker 来实现持续集成Asp.NET Core项目(当然 也可以是任意项目). 打算用三个篇幅来记录完整的全过程 觉得有帮助的朋友~可以左上 ...
- asp.net core 身份认证/权限管理系统简介及简单案例
如今的网站大多数都离不开账号注册及用户管理,而这些功能就是通常说的身份验证.这些常见功能微软都为我们做了封装,我们只要利用.net core提供的一些工具就可以很方便的搭建适用于大部分应用的权限管理系 ...
- (1)ASP.NET Core 应用启动Startup类简介
1.前言 Core与早期版本的 ASP.NET 对比,配置应用程序的方式的 Global.asax.FilterConfig.cs和RouteConfig.cs 都被Program.cs 和 Star ...
- ASP.NET Core 装X利器SignalR:电子画板
电子画板开发需求 教师端需求: 教师登录后能创建房间(教室) 学生加入房间后有通知提醒 教师能够解散房间 基本的画板功能 学生端需求: 能够切换不同在线的房间 能够收到新建房间的通知 能够收到房间 ...
- ASP.NET CORE 2.0 Uses SignalR Technology
https://www.codeproject.com/Articles/1208322/ASP-NET-CORE-Uses-SignalR-Technology
随机推荐
- SSH框架组建时碰到的一些问题
以前用spring+hibernate的框架解决后台事务,这一次重新组建框架,计划引入Struts,如果方便的话,可能会进一步引入Freemarker.以下记下配置中的一些问题及解决,以供他人参考. ...
- Resin文档阅读笔记
阅读文档对应的版本为Resin4.0,且基本只关注Standard版本的功能. 1.Resin可以注册为服务: To install the service, use C:/> resin-3. ...
- Maven编译中的一些坑
错误1: invalid LOC header 这个错误比较好解决,jar下载不完全,去到相应的Maven包目录,把东西删掉重新编译就行. 错误2: java.lang.TypeNotPresentE ...
- Java 重入锁 ReentrantLock 原理分析
1.简介 可重入锁ReentrantLock自 JDK 1.5 被引入,功能上与synchronized关键字类似.所谓的可重入是指,线程可对同一把锁进行重复加锁,而不会被阻塞住,这样可避免死锁的产生 ...
- Scala编程入门---面向对象编程之Trait
Scala中Trait是一种特殊概念 首先我们可以将Triat做为接口来使用,此时的Triat就与java中的接口非常相似 在Triat中可以定义抽象方法,就与抽象类中的抽象方法一样,只要不给出具体的 ...
- Java获取当日的起始时间,结束时间,现在时间,是否在时间段中。
当日的起始时间 public static Date getTodayStartTime() { Calendar todayStart = Calendar.getInstance(); today ...
- 通过Django Channels设计聊天机器人WEB框架
这两个月都在忙着设计针对银联客服业务的智能聊天机器人,上一周已经交完设计报告,这一周还和部门同事一起分享了系统设计及运行效果.因为时间的关系,系统原型我使用了Flask+jQuery的组合,感觉用以原 ...
- 在UltraEdit中如何像NotePad++一样实现双击单词在全文中高亮
NotePad++中有个功能特别好用,就是双击某个单词,这个单词就会在全文档中高亮,如下图 我经常用UltraEdit,结果是UE中没有这个功能,这么实用的功能居然没有? 没关系,在UE中shift+ ...
- HTML标签fieldset
一个不常用的HTML标签fieldset,不过我觉得比较有意思,其语法如下: <fieldset> <legend>fieldset名称</legend> < ...
- redis的持久化之RDB的配置和原理
Redis优秀的性能是由于其将所有的数据都存储在内存中,同样memcached也是这样做的,内存中的数据会在服务器重启后就没有了,也就是不能保证持久化.但是为什么Redis能够脱颖而出呢,很大程度上是 ...