从壹开始 [Admin] 之四 || NetCore + SignalR 实现日志消息推送

缘起

哈喽大家周一好呀,感觉好久没有写文章了,上周出差了一次,感觉还是比坐办公室好的多,平时在读一本书《时生》,感兴趣的可以看看??......

这几天翻看 NetCore 相关知识扩展的时候,发现了久违的一个知识点 —— SignalR ,为啥说久违呢,因为去年的时候,我在公司的项目里就想用了,后来组员说他学学看,也没有了下文,我也就耽搁了,昨天突然看到这个了,想着正好看看吧,尽量落地到 NetCore 项目上,当时我很自信的以为这个技术很老了,应该用的人很多,可是天不遂人愿,在.Net MVC中使用的很多有六成,在NetCore 的小demo有两成,NetCore + Vue 一起使用的就是寥寥无几了,而且更多的是仿照官网的,好吧,我就简单写一个吧,希望对大家有所帮助,尽量将这个技术落地。

你一定很好奇,为啥要学 SignalR ,或者说它有啥作用,那我先说几个场景,你就知道了:

1、用户登录处理相关场景; //平时我们是ajax请求,等待后端处理,然后返回 true ,根据返回结果相应处理;

2、后端(c#)强制用户退出登录(js); //这个后端还真没有做过,没啥思路

3、用户支付订单,等待成功后跳转; //我以前用的是 ajax 轮询,额。。。

4、给用户发消息,或网页内简单的聊天;

5、秒杀用户名单,在页面实时进行滑动展示;

大家从这几个栗子中,可以看到一个共性:

就是想用后端来操作前端,也就是说可以通过 服务端代码,来控制前端 js 事件,来实现响应式的实时场景过程,用户完全不用做任何操作,或者做少量的操作就能实现更多的效果。

大家可以先自己用自己平时的想法和经验来实现上边的场景,当然并不是一定使用 SignalR ,Scoket 现在也是很火,本文就是简单说说 SignalR 的基础用法,想了想,怎么才能让这个技术落地,最后决定将全部的操作日志通过 SignalR 的形式在Admin后台展示出来吧,以后也试试强制登录的功能,请看:

动图:

一、什么是SignalR?

1、基本概念

本文重点说如何使用,但是为了文章的完整性,还是粘贴了一些概念讲解,参考《ASP.NET Core SignalR 简介》,更多的知识点请自行研究吧,网上这种概念类文章很多:

ASP.NET Core SignalR 是一个开源代码库,它简化了向应用添加实时 Web 功能的过程。 实时 Web 功能使服务器端代码能够即时将内容推送到客户端。

SignalR的可使用Web Socket, Server Sent Events 和 Long Polling作为底层传输方式。

SignalR 的适用对象:

  • 需要来自服务器的高频率更新的应用。 例如:游戏、社交网络、投票、拍卖、地图和 GPS 应用。
  • 仪表板和监视应用。 示例包括公司仪表板、销售状态即时更新或行程警示。
  • 协作应用。 协作应用的示例包括白板应用和团队会议软件。
  • 需要通知的应用。 社交网络、电子邮件、聊天、游戏、行程警示以及许多其他应用都使用通知。

SignalR 提供了一个用于创建服务器到客户端 《远程过程调用(RPC》的 API。 RPC 通过服务器端 .NET Core 代码调用客户端上的 JavaScript 函数。

以下是 ASP.NET Core SignalR 的一些功能:

  • 自动管理连接。
  • 同时向所有连接的客户端发送消息。 例如,聊天室。
  • 将消息发送到特定的客户端或客户端组。
  • 扩展以处理增加的流量。

为啥要使用它,因为它是微软的。

2、支持平台

服务端:ASP.NET Core SignalR 适用于 ASP.NET Core 支持的任何服务器平台。

JS 客户端:需要支持NodeJS 8+、或者常见主流浏览器都支持。

Java 客户端:支持Java 8或更高版本。

Net 客户端:可以在 ASP.NET Core 支持的任何平台上运行。 例如, Xamarin 开发人员可以使用 SignalR用于构建 Android 应用程序使用 Xamarin.Android 8.4.0.1 或更高版本和 iOS 应用程序使用 Xamarin.iOS 11.14.0.4 或更高版本。如果服务器运行 IIS,Websocket 传输要求安装 IIS 8.0 或更高版本在 Windows Server 2012 或更高版本。 其他传输在所有平台上都受支持。

3、回落机制

参考文章《SignalR简介及使用

SignalR使用的三种底层传输技术分别是Web Socket, Server Sent Events 和 Long Polling;

其中Web Socket仅支持比较现代的浏览器,Web服务器也不能太老;

而Server Sent Events 情况可能好一点, 但是也存在同样的问题。

Web Socket是最好的最有效的传输方式, 如果浏览器或Web服务器不支持它的话, 就会降级使用SSE, 实在不行就用Long Polling;

一旦建立连接, SignalR就会开始发送keep alive消息, 来检查连接是否还正常, 如果有问题, 就会抛出异常;

因为SignalR是抽象于三种传输方式的上层, 所以无论底层采用的哪种方式, SignalR的用法都是一样的;

SignalR默认采用这种回落机制来进行传输和连接。但是也可以禁用回落机制, 只采用其中一种传输方式。

4、Hub组件

Hub是SignalR的一个组件, 它运行在ASP.NET Core应用里. 所以它是服务器端的一个类;

Hub使用RPC接受从客户端发来的消息, 也能把消息发送给客户端, 所以它就是一个通信用的Hub;

在ASP.NET Core里, 自己创建的Hub类需要继承于基类Hub;

在Hub类里面, 我们就可以调用所有客户端上的方法了, 同样客户端也可以调用Hub类里的方法;

之前说过方法调用的时候可以传递复杂参数, SignalR可以将参数序列化和反序列化, 这些参数被序列化的格式叫做Hub 协议,所以Hub协议就是一种用来序列化和反序列化的格式;

Hub协议的默认协议是JSON, 还支持另外一个协议是MessagePack, MessagePack是二进制格式的, 它比JSON更紧凑, 而且处理起来更简单快速, 因为它是二进制的;

此外, SignalR也可以扩展使用其它协议。

好啦,复杂而又枯燥的概念说完了,接下来咱们开始动手写代码了!(额概念还是要看的??)

二、搭建 SignalR 服务中心

既然要实现实时交互,肯定得有服务端,那我们就直接在 Blog.Core 项目上,进行处理吧

1、引用 SignalR 包

为了以后好拓展,我就把 SignalR 中心,也可以是通讯管道定义到了 Common 层,当然可以自定义任意层。

//请看清,还有一个 Net 版本的,但是也能用,还是用 core 版本的吧
Install-Package Microsoft.AspNetCore.SignalR

2、声明 Hub 管道——集线器

在 Blog.Core.Common 层,新建一个 Hubs 文件夹,然后添加一个 ChatHub 类:

 public class ChatHub : Hub
 {
     public async Task SendMessage(string user, string message)
     {
         await Clients.All.SendAsync("ReceiveMessage", user, message);
     }

     //定于一个通讯管道,用来管理我们和客户端的连接
     //1、客户端调用 GetLatestCount,就像订阅
     public async Task GetLatestCount(string random)
     {
         //2、服务端主动向客户端发送数据,名字千万不能错
         await Clients.All.SendAsync("ReceiveUpdate", LogLock.GetLogData());

         //3、客户端再通过 ReceiveUpdate ,来接收

     }
 }

基本的概念已经在上边了,大家结合之前的概念,应该能看懂,看不懂也没事儿,等看了下边的 Vue 代码,就理解了。

旁白:

这里说一下,上文中的GetLogData,这个方法,是直接把我们之前的日志从log文件给提取出来了,包括AOP日志,异常日志,Sql日志,因为格式规则变了,如果你本地已经存在之前的错误日志了,请删了文件重新生成,否则格式不正确会报错。

3、配置服务 与 中间件

还是老规则,在netcore 中,基本只要涉及到Http请求相关的,一定要配置中间件,任何需要在宿主中用的服务,都需要注入:

//这个配置就太简单了,不细说了,大家一看就知道往哪里放
services.AddSignalR();

 app.UseMvc();

//我这个放到了 Mvc 管道下边,上边好像也可以
 app.UseSignalR(routes =>
 {
     //这里要说下,为啥地址要写 /api/xxx
     //因为我前后端分离了,而且使用的是代理模式,所以如果你不用/api/xxx的这个规则的话,会出现跨域问题,毕竟这个不是我的controller的路由,而且自己定义的路由
     routes.MapHub<ChatHub>("/api/chatHub");
 });

4、跨域

这一块大家肯定都已经配置好了,要不然不会前后端分离的,至于用前端 proxy 代理,还是后端 CORS 配置,看自己喜好吧,我更喜欢前者。

这个时候,我们的后端通道就打通了,如何验证呢,我们在路由器直接输入上边的自定义路由地址即可:

因为每次请求需要一个 ID 号的,直接访问肯定不行,那这个 ID 我们怎么来拿呢,别着急,下文会说到,重点来了。

三、在 Vue 中配置客户端连接

服务端可以了,那就改配置客户端了,其实客户端特别简单,就好像我们使用一个js库插件一样,比如大家一定用过地图api库 ,直接引用js,然后new map对象即可使用了,没错,SignalR和它一毛一样。

1、安装库依赖包

现在 vue 也和 core 很像了,用一个东西,都需要安装包,配置服务,再调用这三部曲了。

//直接在项目中执行
npm install @aspnet/signalr

我为了更好的让大家理解这个通讯的过程,每个标题后边,都破折号了我对这个过程的理解,大家一看就懂了。

2、添加引用——买个手机

在Admin 项目里,我增加了一个展示日志的页面,大家自己看看就都懂了,然后之前是需要每次刷新的,但是这次改造成可以自推送的。

上边也说到了,这个 SignalR 我们只需要像 map 地图那样,引用就行了,很简单:

网上很坑的是,很多教程里竟然要在 main.js 中引用,最后导致还出现了依赖 Jquery 的各种bug,大家如果无聊可以试试。

3、开始连接到中心——连上网络

直接上代码:

 created: function () {
     //1、首先我们实例化一个连接器
     this.connection = new signalR.HubConnectionBuilder()
         //然后配置通道路由
         .withUrl(‘/api/chatHub‘)
         //日志信息
         .configureLogging(signalR.LogLevel.Information)
         //创建
         .build();

     var thisVue = this;
     //开始连接
     thisVue.connection.start();
 },

是不是很简单,只需要我们在页面初始化的时候,创建连接即可,只不过这里有一些小问题,

还记得上边咱们在 startup.cs 中配置的 hub 路由么,如果我们不使用 /api/chatHub 会是怎么样呢?这里我也简单把错误的给写出来,留作参考:

1、相对路径,没用代理规则:

withUrl(‘/axxxxx/chatHub‘)

是因为我们用的相对路径,而且也没与代理,系统会认为我们访问的是一个页面路由,所以 404;

2、绝对路径,没用代理规则

withUrl(‘http://localhost:8081/axxxxx/chatHub‘)

这样就会出现代理的问题。

当然!如果你使用的是后端 CORS 机制跨域,不会这个问题的,其他的各种情况自己把握就好。

是不是我们这么配置好了就没事了呢,别着急,还有要给bug,

如果你在服务器里用的是 Nginx 做代理的话,可能会遇到这个问题:

大家可以看看,这个错误,和上边两个都不一样,是已经连上了,但是去不能开启数据 的交互 transport !神奇,简单的看了看开源的 websockets 上提的 issues,是这么解决的《wss: Error during WebSocket handshake: Unexpected response code: 200 #979》

好啦!这次应该没啥问题了,继续往下走。

4、客户端调用集线器——呼叫对方

那我们现在已经连接成功了,剩下的就是调用集线器了,也就是上边我们定义的 Hub 通道,用来接收日志:

mounted() {

    thisVue.connection.on(‘ReceiveUpdate‘, function (update) {
        console.info(‘update success!‘)
        thisVue.tableData = update;
        window.clearInterval(this.t)
    })

},

5、从集线器调用客户端方法——接收回应

上边我们是从客户端去订阅了一个 通道 连接,也就是说,我需要这个约定,那约定成功后,就需要接收来自服务器的通讯返回结果了,

thisVue.connection.on(‘ReceiveUpdate‘, function (update) {
    console.info(‘update success!‘)
    thisVue.tableData = update;//将返回的数据,赋值给当前页面data
})

这个时候我们刷新页面,已经能看到消息了,然后我们在看看接口请求:

是不是很熟悉!没错,这个就是我们上边说到的那个 ID ,不记得的往上看,这个是自动生成的,而且不随着消息推送而变化,只有每次请求重新连接的时候,才会变化。

好啦,这样我们就成功了在页面上展示出了我们的数据,BUT!别慌,好像还没有完成,因为我们现在仅仅是展示了出来,还没有实现推送啊!别着急,既然一次能显示,那多次也能显示。

6、每次更新日志,推送到客户端——实时短信

这个就很简单了,我们只需要在每次日志产生的时候,来推送出来即可,举个全局异常的栗子吧:

先注入我们的通道上下文:

 private readonly IHubContext<ChatHub> _hubContext;

 public GlobalExceptionsFilter(IHostingEnvironment env, ILoggerHelper loggerHelper,
IHubContext<ChatHub> hubContext)
 {
     _env = env;
     _loggerHelper = loggerHelper;
     _hubContext = hubContext;
 }

然后直接使用:

//采用log4net 进行错误日志记录
_loggerHelper.Error(json.Message, WriteLog(json.Message, context.Exception));

_hubContext.Clients.All.SendAsync("ReceiveUpdate", LogLock.GetLogData()).Wait();

这样,每次我们操作的时候,就会触发生成日志的功能,同时再触发推送功能,就这样,我们把消息及时的推送了出去,达到了目的,实现了文章开头的功能。

如果想中断连接,只需要页面关闭的时候,执行 connection.stop() 即可。

四、模拟登录

在文章开头,我说了几个场景,其他的不好实现,先来个模拟登录吧,就是把用户名密码传到后台,然后后台将结果推送回来。

具体的流程就不说了,和上边的是一样的,只是很简单的一个动作,接收下数据即可,

五、结语

今天很简单的实现了两个小功能,一个是模拟登录,一个是实时推送消息,大家学会了么,这里有几个问题,大家可以思考思考:

1、SignalR到底能在平时开发中,使用哪些地方?

2、服务中心是如何将消息发出去的?

3、客户端是如何来订阅某一个通道集线器的?

4、SignalR的底层原理是什么?

5、如何关闭连接?

六、Github && Gitee

NetCore https://github.com/anjoy8/Blog.Core

Vue https://github.com/anjoy8/Blog.Admin

------♥------♥------♥----------

原文地址:https://www.cnblogs.com/laozhang-is-phi/p/netcore-vue-signalr.html

时间: 2024-10-29 15:31:09

从壹开始 [Admin] 之四 || NetCore + SignalR 实现日志消息推送的相关文章

vue js 和signalr 结合实现消息推送1

由于signalr2.2.0 依赖于jQuery,虽然在vuejs 略显臃肿, 但是对于目前刚接触 vuejs 和想实现 前后分离的我来说 这已经很好了.目前先实现功能, 然后如果有时间或者期望大牛将signalr 改成不依赖jQuery的signalr.项目结构是分服务端asp.net webAPI 前端vuejs.所以牵扯到跨域的问题,但是目前的signalr 版本已经支持,只有服务端支持跨域就可以了.由于时间关系先简略记下当前的主要解决方法. 服务端: asp.net webapi 1 u

AngularJS+ASP.NET MVC+SignalR实现消息推送

原文:http://www.mincoder.com/article/4565.shtml 背景 OA管理系统中,员工提交申请单,消息实时通知到相关人员及时进行审批,审批之后将结果推送给用户. 技术选择 最开始发现的是firebase,于是很兴奋的开始倒腾起来.firebase用 起来倒是简单:引用一个js即可,按官网上的教程很快便应用到了项目中.第二天打开项目发现推送功能不好使了,这是为何?最后发现firebase官网打 不开了...难道firebase被google收了也会被天朝给墙掉?也许

Asp.net SignalR 实现服务端消息推送到Web端

原文:http://www.cnblogs.com/wintersun/p/4148223.html 之前的文章介绍过Asp.net SignalR,  ASP .NET SignalR是一个ASP .NET 下的类库,可以在ASP .NET 的Web项目中实现实时通信.  今天我们来实现服务端消息推送到Web端,   首先回顾一下它抽象层次图是这样的: 实际上 Asp.net SignalR 2 实现 服务端消息推送到Web端, 更加简单. 为了获取更好的可伸缩性, 我们引入消息队列, 看如下

Signalr实现消息推送

一.前言 大多数系统里面好像都有获取消息的功能,但这些消息来源都不是实时的,比如你开两个浏览器,用两个不同的账号登录,用一个账号给另外一个账号发送消息,然而并不会实时收到消息,必须要自己手动F5刷新一下页面才会显示自己的消息,这样感觉用户体验不太好.之前看了Learning hard关于Signalr的文章,刚好自己项目中有用到获取实时消息的功能,然而我们项目中就是用js代码setinterval方法进行1秒刷新读取数据的,这样严重给服务器端添加负担,影响系统性能!所以自己稍微研究了一下,下面是

asp.net使用signalr实现集群集群下面的消息推送

1.选用Signalr的原因 Signalr内部给我们做了很多封装.当服务器或者浏览器不支持websoket协议的时候就使用长连接方式  不支持长连接再选用轮询的方式获取消息 websoket:与服务器保持长连接 服务器和客户端可以进行双工通讯而不用建立新的链接 长连接:服务器与客户端保持长连接 .每隔一段时间客户端询问服务器  而不用建立新连接 轮询:客户端定期向服务器发送请求询问 每次都会建立新的链接(建立新的链接使非常耗时的) 2.集群情况下的遇到的难点 当一个一台服务器的给某个用户发送了

基于SignalR的消息推送与二维码描登录实现

1 概要说明 使用微信扫描登录相信大家都不会陌生吧,二维码与手机结合产生了不同应用场景,基于二维码的应用更是比较广泛.为了满足ios.android客户端与web短信平台的结合,特开发了基于SinglarR消息推送机制的扫描登录.本系统涉及到以下知识点:     SignalR:http://signalr.net/ 这官网,ASP.NET SignalR 是为 ASP.NET 开发人员提供的一个库,可以简化开发人员将实时 Web 功能添加到应用程序的过程.实时 Web 功能是指这样一种功能:当

SignalR Self Host+MVC等多端消息推送服务(1)

一.概述 由于项目需要,最近公司项目里有个模块功能,需要使用到即时获得审批通知:原本的设计方案是使用ajax对服务器进行定时轮询查询,刚刚开始数据量和使用量不大的时候还好,后来使用量的增加和系统中各种业务的复杂度增加,服务器的压力也越来越大,于是我想使用消息推送的方式替换掉ajax轮询查询,当有审批提交时,调用推送方法,将消息推送到下一审批人那,这样就减低了服务器的压力. Signal 是微软支持的一个运行在.NET平台上的 html websocket 框架.它出现的主要目的是实现服务器主动推

SignalR Self Host+MVC等多端消息推送服务(2)

一.概述 上次的文章中我们简单的实现了SignalR自托管的服务端,今天我们来实现控制台程序调用SignalR服务端来实现推送信息,由于之前我们是打算做审批消息推送,所以我们的demo方向是做指定人发送信息,至于做聊天消息和全局广播,这里就不在进行演示了. 二.创建控制台客户端 1.在SignalRProject解决方案下新建一个名为Clinet的控制台 2.在程序包管理控制台中输入以下命令 1 Install-Package Microsoft.AspNet.SignalR.Client 3.

SignalR SelfHost实时消息,集成到web中,实现服务器消息推送

先前用过两次SignalR,但是中途有段时间没弄了,今天重新弄,发现已经忘得差不多了,做个笔记! 首先创建一个控制台项目Nuget添加引用联机搜索:Microsoft.AspNet.SignalR.SelfHostMicrosoft.Owin.Cors 在Program.cs添加代码 添加一个Hub 这个hub里面我们就实现了连接时候服务器像客户端推送一条消息,客户端接收方法为receive下面我又给这个hub添加了一个send方法,客户端发送消息来的时候会把消息广播到所有客户端去,代码如下: