什么是 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执行成功执行
  $.ajax({
            success: function (response) {              
                     connection.start().then(function () {
                            connection.invoke('SetConnectionMaps', response.data.account);
                    }
                },
            });
     

首先你要了解到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 :学习消息通讯,实现一个消息通知的更多相关文章

  1. ASP.NET Core SignalR中的流式传输

    什么是流式传输? 流式传输是这一种以稳定持续流的形式传输数据的技术. 流式传输的使用场景 有些场景中,服务器返回的数据量较大,等待时间较长,客户端不得不等待服务器返回所有数据后,再进行相应的操作.这时 ...

  2. Asp.Net Core SignalR 用泛型Hub优雅的调用前端方法及传参

    继续学习 最近一直在使用Asp.Net Core SignalR(下面成SignalR Core)为小程序提供websocket支持,前端时间也发了一个学习笔记,在使用过程中稍微看了下它的源码,不得不 ...

  3. Asp.Net Core SignalR 与微信小程序交互笔记

    什么是Asp.Net Core SignalR Asp.Net Core SignalR 是微软开发的一套基于Asp.Net Core的与Web进行实时交互的类库,它使我们的应用能够实时的把数据推送给 ...

  4. ASP.NET Core SignalR

    ASP.NET Core SignalR 是微软开发的一套基于ASP.NET Core的与Web进行实时交互的类库,它使我们的应用能够实时的把数据推送给Web客户端. 功能 自动管理连接 允许同时广播 ...

  5. Asp.Net Core WebApi学习笔记(四)-- Middleware

    Asp.Net Core WebApi学习笔记(四)-- Middleware 本文记录了Asp.Net管道模型和Asp.Net Core的Middleware模型的对比,并在上一篇的基础上增加Mid ...

  6. ASP.NET Core SignalR:基础概述

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

  7. 使用websocket连接(对接)asp.net core signalr

    使用通用websocket连接asp.net core signalr 一.背景介绍 signalr的功能很强大,可以为我们实现websocket服务端节省不少的时间.但是可能由于不同的环境,我们在对 ...

  8. ASP.NET CORE使用WebUploader对大文件分片上传,并通过ASP.NET CORE SignalR实时反馈后台处理进度给前端展示

    本次,我们来实现一个单个大文件上传,并且把后台对上传文件的处理进度通过ASP.NET CORE SignalR反馈给前端展示,比如上传一个大的zip压缩包文件,后台进行解压缩,并且对压缩包中的文件进行 ...

  9. 学习ASP.NET Core Blazor编程系列二——第一个Blazor应用程序(中)

    学习ASP.NET Core Blazor编程系列一--综述 学习ASP.NET Core Blazor编程系列二--第一个Blazor应用程序(上) 四.创建一个Blazor应用程序 1. 第一种创 ...

  10. [asp.net core]SignalR一个例子

    摘要 在一个后台管理的页面想实时监控一些操作的数据,想到用signalR. 一个例子 asp.net core+signalR 使用Nuget安装包:Microsoft.AspNetCore.Sign ...

随机推荐

  1. 感谢ZhangYu dalao回关

  2. python机器学习——使用scikit-learn训练感知机模型

    这一篇我们将开始使用scikit-learn的API来实现模型并进行训练,这个包大大方便了我们的学习过程,其中包含了对常用算法的实现,并进行高度优化,以及含有数据预处理.调参和模型评估的很多方法. 我 ...

  3. python经典面试算法题1.3:如何计算两个单链表所代表的数之和

    本题目摘自<Python程序员面试算法宝典>,我会每天做一道这本书上的题目,并分享出来,统一放在我博客内,收集在一个分类中. 1.2 如何实现链表的逆序 [华为笔试题] 难度系数:⭐⭐⭐ ...

  4. 关闭redis持久化功能

    关闭redis持久化功能持久化会报如下信息 会影响硬盘写入性能 所以没什么用 就关掉吧 修改redis配置文件,redis.conf 第115行左右. 1.注释掉原来的持久化规则 <pre> ...

  5. 痞子衡嵌入式:串行EEPROM接口事实标准及SPI EEPROM简介

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是EEPROM接口标准及SPI EEPROM. 痞子衡之前写过一篇文章 <SLC Parallel NOR简介>,介绍过并行N ...

  6. 结合参数接收响应转换原理讲解SpringBoot常用注解

    一.常用注解回顾 1.1 @RequestBody与@ResponseBody //注意并不要求@RequestBody与@ResponseBody成对使用. public @ResponseBody ...

  7. MySQL数据库root账户密码忘记两种处理方法(保有效)

    方法1: 1.停止MySQL服务 # kill `cat /var/run/mysqld/mysqld.pid` 或者 # pkill mysqld 2.创建一个密码赋值语句的文本文件 # vi my ...

  8. shell脚本2——控制语句

    1.顺序结构体 命令从上往下顺序执行 2.分支结构体 1)判断真假 test 表达式 或者 [ 表达式 ](必须有空格) 真返回0,假返回1 test的别名是[, 参数是] 判断表达式 记忆 解释 ! ...

  9. 发送大数据时,PDU的问题?

    昨天发现通过 Ice发送请求传递一个大块数据时,当请求的体积大于1.2M后,直接抛出异常Connection Lost,对方peer或是断开了.通过防火墙配置排查,以及对同一网络同一机器的php服务p ...

  10. ndk编译出来的executable动态库入口函数的参数错乱

    早些时间用ndk编译带main入口函数的动态库,测试可运行.今天要作它用时,发现在这个入口函数并没有传入正确的参数. hello.cpp有main函数,用ndk分别编译成可执行文件和动态库文件,使两者 ...