ASP.NET Core SignalR :学习消息通讯,实现一个消息通知
什么是 SignalR
目前我用业余时间正在做一个博客系统,其中有个功能就是评论通知,就是假如A用户评论B用户的时候,如果B用户首页处于打开状态,那么就会提示B用户有未读消息。暂时用SignalR来实现这个功能。我也是看了两天的资料才明白怎么去使用。
关于SignalR的理论知识可以去官网或者百度,我这里只是结合自己的功能来分享下,如果有错,请原谅指出。
下载js
SignalR是需要微软提供的js,因为我的项目是前后端分离的,所以我是单独下载到一个文件夹,然后复制js到我的前端项目里。只需要signalr.js
页面加载创建连接
- //创建连接
var connection = new signalR.HubConnectionBuilder().withUrl('http://127.0.0.1:5000/chatHub').build();
//ajax执行成功执行
首先你要了解到SignalR基本运行的原理,官网:https://docs.microsoft.com/zh-cn/aspnet/core/tutorials/signalr?view=aspnetcore-3.1&tabs=visual-studio
你可以直接继承Hub这个类,我这里用的是强类型Hub<T>,我就是为了让前端和后端统一下。刚开始Hub<T>我纠结了好久,不知道怎么用,最后我手动做了下,认为它只是为了方便前端和后端统一。
如果你只是简单的继承Hub类,你就必须调用SendAsync方法,并且指定前端接收触发的方法名称“InvokeMessage”,如果你后端和前端名字对应不上,就会有问题。
- public class SingalrService : Hub
- {
- private ISingalrSvc _singalrSvc;
- public SingalrService(ISingalrSvc singalrSvc)
- {
- _singalrSvc = singalrSvc;
- }
- public async Task SendMessageAsync(Message sendMessage)
- {
- await Clients.All.SendAsync("InvokeMessage",sendMessage);
- }
- public void SetConnectionMaps(string account)
- {
- string connectionid = Context.ConnectionId;
- _singalrSvc.SetConnectionMaps(connectionid, account);
- }
- public override Task OnDisconnectedAsync(Exception exception)
- {
- _singalrSvc.Remove(Context.ConnectionId);
- return base.OnDisconnectedAsync(exception);
- }
- }
所以有了强类型Hub<T>,自己定义一个接口,提过方法InvokeMessage供前前端调用。
- /// <summary>
- /// 客户端js调用方法
- /// </summary>
- public interface ISingalrClient
- {
- Task InvokeMessage(Message sendMessage);
- }
- public class SingalrService : Hub<ISingalrClient>
- {
- private ISingalrSvc _singalrSvc;
- public SingalrService(ISingalrSvc singalrSvc)
- {
- _singalrSvc = singalrSvc;
- }
- public void SetConnectionMaps(string account)
- {
- string connectionid = Context.ConnectionId;
- _singalrSvc.SetConnectionMaps(connectionid, account);
- }
//连接中断时执行,微软这样描述的:
//重写OnDisconnectedAsync
虚方法,以便在客户端断开连接时执行操作。 如果客户端故意断开连接(例如,通过调用connection.stop()
),exception
参数将null
。
//但是,如果客户端由于错误(例如网络故障)而断开连接,则exception
参数将包含描述失败的异常- public override Task OnDisconnectedAsync(Exception exception)
- {
- _singalrSvc.Remove(Context.ConnectionId);
- return base.OnDisconnectedAsync(exception);
- }
- }
这个时候一个用户打开了首页,然后首页有个js方法来初始化连接,同一个页面内的connectionid是一样的,每次刷新或新打开一个窗口的新页面的connectionid是不一样的,并且你刷新页面或者关掉会认为是连接中断,会执行OnDisconnectedAsync方法,这个方法时SingalR自带的,它是个虚方法,你也可以重写,就像我一样。我这里的代码逻辑是将连接id和当前登录人作为键值对存入内存,然后用户关掉页面就会执行OnDisconnectedAsync方法,将相关的coonectionid从内存删掉:
- layui.use(['element', 'layer'], function () {
var element = layui.element;- element.render('nav');
- initLoad();
//初始化连接,每个页面的connection的connectionid是一样的,但是每次创建的不一样- var connection = new signalR.HubConnectionBuilder().withUrl('http://127.0.0.1:5000/chatHub').build();
//绑定后台触发的方法,前面已经讲过了,具体业务还没实现,- connection.on('InvokeMessage', (reviceMessage) => {
- var v = reviceMessage;
- });
- $.ajax({
- url: url + 'user/userInfo',
- type: 'get',
- dataType: 'json',
- beforeSend: function (xhr) {
- doBeforeSend(xhr);
- },
- success: function (response) {
- if (response.code == '1') {
- $("#nologin").show();
- $("#user").hide();
- }
- else {
- $("#nologin").hide();
- $("#user").show();
- $("#photo").attr('src', response.data.headPhoto);
//连接开始- connection.start().then(function () {
//调用后台方法,不是api接口,将当前登录人账号传过去- connection.invoke('SetConnectionMaps', response.data.account);
- })
- }
- },
- complete: function (xhr) {
- doComplete(xhr);
- },
- });
- });
这个时候连接已经创建完成,并且用户并没有关闭首页,连接一直处于连接状态。这个时候另一个用户打开了一篇文章详情,并且对它评论提交内容后,我让它触发了一个连接SingalR的事件,
- form.on('submit(review)', function (data) {
- loading = layer.load(2);
- var commentModel = {
- 'Content': data.field.desc,
- }
- $.ajax({
- url: url + 'article/review/' + id,
- contentType: 'application/json; charset=utf-8',
- type: 'post',
- datatype: 'json',
- data: JSON.stringify(commentModel),
- beforeSend: function (xhr) {
- doBeforeSend(xhr);
- },
- success: function (response) {
- if (response.code == 0) {
- //另一个用户创建了连接
- var connection = new signalR.HubConnectionBuilder().withUrl('http://127.0.0.1:5000/chatHub').build();
- connection.start().then(function () {
- var apiRoute=url+'Singalr/admin';//admin是我设置死的,实际应该是自己判断,会调用下面的api,[Route("api/[controller]")],SingalR也是支持api调用的
- var token=localStorage.getItem('token');
- fetch(apiRoute,{
- method:'get',
- headers:{
- 'Authorization':'Bearer ' + token
- }
- })
- event.preventDefault();
- })
- layer.close(loading);
- } else {
- layer.close(loading);
- layer.msg("评论失败", {
- icon: 5
- });
- }
- },
- complete: function (xhr) {
- doComplete(xhr);
- },
- })
- [ApiController]
- public class SingalrController : ControllerBase
- {
- private IHubContext<SingalrService, ISingalrClient> _hubContext;
- private ISingalrSvc _singalrSvc;
- public SingalrController(IHubContext<SingalrService, ISingalrClient> hubContext, ISingalrSvc singalrSvc)
- {
- _hubContext = hubContext;
- _singalrSvc = singalrSvc;
- }
- /// <summary>
- /// 查询未处理数量
- /// </summary>
- /// <param name="account"></param>
- /// <returns></returns>
- [HttpGet("{account}")]
- public async Task NewsCount(string account)
- {
- Message sendMessage = new Message();
- sendMessage.Data = "11";
//刚已经讲了,用户加载首页的时候已经把connectionid和account存入到了内存里面,现在再取用户相关的connectionID,如果直接调用Clinets.ALL就是给所有客户端发送消息- IReadOnlyList<string> connectionIds = (IReadOnlyList<string>)_singalrSvc.GetConnectionIds(account);
- await _hubContext.Clients.Clients(connectionIds).InvokeMessage(sendMessage);
- }
- }
这个时候调用了这个api执行了里面的_hubContext.Clients.Clients(connectionIds).InvokeMessage(sendMessage),connectionIds是根据业务逻辑所判断的触发的那些客户端;然后前端会根据方法名响应对应的js代码,如下
- layui.use(['element', 'layer'], function () {
- var element = layui.element;
- element.render('nav');
- initLoad();
- var connection = new signalR.HubConnectionBuilder().withUrl('http://127.0.0.1:5000/chatHub').build();
- //我认为是一个用来侦听服务端方法的js
- connection.on('InvokeMessage', (reviceMessage) => {
- var v = reviceMessage;
//响应后端方法成功后,就开始自己的业务逻辑- });
- $.ajax({
- url: url + 'user/userInfo',
- type: 'get',
- dataType: 'json',
- beforeSend: function (xhr) {
- doBeforeSend(xhr);
- },
- success: function (response) {
- if (response.code == '1') {
- $("#nologin").show();
- $("#user").hide();
- }
- else {
- $("#nologin").hide();
- $("#user").show();
- $("#photo").attr('src', response.data.headPhoto);
- connection.start().then(function () {
- connection.invoke('SetConnectionMaps', response.data.account);
- })
- }
- },
- complete: function (xhr) {
- doComplete(xhr);
- },
- });
- });
游戏也能赚钱?如果你热爱游戏,并且想通过游戏赢得零花钱,5173是个不错的选择 http://www.5173.com/?recommenduserid=US15061749098191-04F6
ASP.NET Core SignalR :学习消息通讯,实现一个消息通知的更多相关文章
- ASP.NET Core SignalR中的流式传输
什么是流式传输? 流式传输是这一种以稳定持续流的形式传输数据的技术. 流式传输的使用场景 有些场景中,服务器返回的数据量较大,等待时间较长,客户端不得不等待服务器返回所有数据后,再进行相应的操作.这时 ...
- Asp.Net Core SignalR 用泛型Hub优雅的调用前端方法及传参
继续学习 最近一直在使用Asp.Net Core SignalR(下面成SignalR Core)为小程序提供websocket支持,前端时间也发了一个学习笔记,在使用过程中稍微看了下它的源码,不得不 ...
- Asp.Net Core SignalR 与微信小程序交互笔记
什么是Asp.Net Core SignalR Asp.Net Core SignalR 是微软开发的一套基于Asp.Net Core的与Web进行实时交互的类库,它使我们的应用能够实时的把数据推送给 ...
- ASP.NET Core SignalR
ASP.NET Core SignalR 是微软开发的一套基于ASP.NET Core的与Web进行实时交互的类库,它使我们的应用能够实时的把数据推送给Web客户端. 功能 自动管理连接 允许同时广播 ...
- Asp.Net Core WebApi学习笔记(四)-- Middleware
Asp.Net Core WebApi学习笔记(四)-- Middleware 本文记录了Asp.Net管道模型和Asp.Net Core的Middleware模型的对比,并在上一篇的基础上增加Mid ...
- ASP.NET Core SignalR:基础概述
一.简介 ASP.NET Core SignalR 是一个开源代码库,它简化了向应用添加实时 Web 功能的过程. 实时 Web 功能使服务器端代码能够即时将内容推送到客户端. SignalR 的适用 ...
- 使用websocket连接(对接)asp.net core signalr
使用通用websocket连接asp.net core signalr 一.背景介绍 signalr的功能很强大,可以为我们实现websocket服务端节省不少的时间.但是可能由于不同的环境,我们在对 ...
- ASP.NET CORE使用WebUploader对大文件分片上传,并通过ASP.NET CORE SignalR实时反馈后台处理进度给前端展示
本次,我们来实现一个单个大文件上传,并且把后台对上传文件的处理进度通过ASP.NET CORE SignalR反馈给前端展示,比如上传一个大的zip压缩包文件,后台进行解压缩,并且对压缩包中的文件进行 ...
- 学习ASP.NET Core Blazor编程系列二——第一个Blazor应用程序(中)
学习ASP.NET Core Blazor编程系列一--综述 学习ASP.NET Core Blazor编程系列二--第一个Blazor应用程序(上) 四.创建一个Blazor应用程序 1. 第一种创 ...
- [asp.net core]SignalR一个例子
摘要 在一个后台管理的页面想实时监控一些操作的数据,想到用signalR. 一个例子 asp.net core+signalR 使用Nuget安装包:Microsoft.AspNetCore.Sign ...
随机推荐
- 修改tomcat默认使用的jdk版本
1.windows平台 在csetclasspath.bat文件开头加上如下两句(指定JDK): set JAVA_HOME=C:\Program Files\Java\jdk1.7.0_79 se ...
- Pandas 转换连接
# 导入相关库 import numpy as np import pandas as pd 拼接 有两个 DataFrame,都存储了用户的一些信息,现在要拼接起来,组成一个 DataFrame. ...
- [考试反思]1109csp-s模拟测试107:低能
诶一看这不是水题AK场吗?然后80分钟就拿到了285分. 然后,对拍?还是卡T2常数?还是想T2正解? 于是上述三项我依次进行了. 前两项让我的分数丝毫不变但是吃掉了我一个多小时的时间. 卡常卡的也不 ...
- re模块的基本使用
目录 re模块 常用元字符 特殊构造 贪婪模式 非贪婪模式 re的常用函数 re模块补充 关于re模块必须知道的知识点 re模块 re模块 , 即正则表达式 , 本身是一种小型的.高度专业化的编程语言 ...
- 极光推送(JPush)开篇
Date:2019-11-11 读前思考: 极光推送是什么? 极光推送是能做什么?有什么优势? 怎么根据业务需求来实现极光推送服务呢? 简介 极光推送(JPush)是独立的第三方云推送平台,致力于为全 ...
- Comparable接口的实现和使用
1.什么是Comparable接口 此接口强行对实现它的每个类的对象进行整体排序.此排序被称为该类的自然排序 ,类的 compareTo 方法被称为它的自然比较方法 .实现此接口的对象列表(和数组)可 ...
- Linux软件包管理和磁盘管理实践
一.自建yum仓库,分别为网络源和本地源 本地yum仓库的搭建就是以下三个步骤: 创建仓库目录结构 上传相应的包到目录下,或者直接挂载光盘也行,如果挂载光盘,第三步就可以省略,因为光盘默认里有repo ...
- Python 基础之socket编程(一)
Python 基础之socket编程(一) 可以进行通信玩儿了,感觉不错不错,网络通信就像打电话,我说一句你听一句之后,你再说一句,我听一句,就这样.....下去了.不扯淡了,来来来,看看今天都搞了点 ...
- 【转载】常见十大经典排序算法及C语言实现【附动图图解】
原文链接:https://www.cnblogs.com/onepixel/p/7674659.html 注意: 原文中的算法实现都是基于JS,本文全部修改为C实现,并且统一排序接口,另外增加了一些描 ...
- 【笔记】nginx部署静态网站
安装nginx 本地到官网下载,然后把压缩包传到服务器上 安装三个依赖 apt-get install libpcre3 libpcre3-dev apt-get install zlib1g-dev ...