首页 > 编程语言 >ASP.NET Core SignalR :学习消息通讯,实现一个消息通知

ASP.NET Core SignalR :学习消息通讯,实现一个消息通知

时间:2024-09-25 12:46:23浏览次数:9  
标签:function Core ASP xhr response SignalR connection singalrSvc public

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执行成功执行
  $.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代码,如下

 

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 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();<br><br>            //我认为是一个用来侦听服务端方法的js             connection.on('InvokeMessage', (reviceMessage) => {                 var v = reviceMessage;<br>                //响应后端方法成功后,就开始自己的业务逻辑             });             $.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

标签:function,Core,ASP,xhr,response,SignalR,connection,singalrSvc,public
From: https://www.cnblogs.com/sexintercourse/p/18431106

相关文章

  • 记.Net Core Host服务使用Dapper内存溢出问题
    背景项目要做一个数据迁移,牵扯大概60多张表,几千万数据,这些数据都被放到了csv文件中并拆分成了10w条记录一个文件。思路是使用.NetCoreHost开一个线程去读取文件夹csv根据业务导入到表就可以。ps:第一次用Dapper做这种处理问题在导入过程中,因为我们的服务器内存只有8G。经常......
  • C#|.net core 基础 - 深拷贝的五大类N种实现方式
    C#|.netcore基础-深拷贝的五大类N种实现方式 合集-C#|.netcore基础(6) 1.C#|.netcore基础-“hello”.IndexOf(“\0”,2)中的坑08-302.C#|.netcore基础-如何判断连续子序列09-033.C#|.netcore基础-值传递vs引用传递09-194.C#|.netcore基础-扩展数......
  • 在不受支持的 Mac 上安装 macOS Sequoia (OpenCore Legacy Patcher v2.0.1)
    在不受支持的Mac上安装macOSSequoia(OpenCoreLegacyPatcherv2.0.1)InstallmacOSonunsupportedMacs请访问原文链接:https://sysin.org/blog/install-macos-on-unsupported-mac/,查看最新版。原创作品,转载请保留出处。作者主页:sysin.orgOpenCoreLegacyPatcher2.0......
  • 在 Windows 机器内使用 Fast API、React、Raspberry Pi 制作服务器应用程序
    系统规格处理器-i5第13代RAM-16GBSSD-Nvme500GB操作系统-WindowsHomeRaspberryPi-Pi48GB我有一个托管的FastAPI应用程序在Windows机器上,同一台机器上还有一个React应用程序。React应用程序使用fastAPI应用......
  • C# .net 8 used Pomelo.EntityFrameworkCore.MySql
    1.dotnetaddpackagePomelo.EntityFrameworkCore.MySqlusingMicrosoft.EntityFrameworkCore;namespaceConsoleApp84{internalclassProgram{staticvoidMain(string[]args){using(varcontext=newDbBookDataContex......
  • asp.net 上传大文件大小控制方案
    原文链接:https://blog.csdn.net/zdw_wym/article/details/7160942需要注意的是:在保存文件时,您应该确保指定文件的完整路径,并确保为ASP.NET使用的帐户提供要存储文件的目录的写权限。上载大文件时,可使用Web.Config元素的maxRequestLength属性来增加文件大小的最大允许值,例如:......
  • RabbitMQ在.net core中的应用
    RabbitMQ是一个可靠且成熟的消息传递和流代理,它很容易部署在云环境、内部部署和本地机器上。它目前被全世界数百万人使用。1.基本概念生产者(Producer)生产者是一个发送消息的程序。发送消息的程序可以是任何语言编写的,只要它能够连接到RabbitMQ服务器,并且能够发送消息到RabbitM......
  • .net core开源工作流程框架elsa源码阅读之容器的理解
    官方文档:https://v3.elsaworkflows.io/这个框架的依赖注入容器,底层是靠原生的IServiceCollection,没有使用其他的三方容器;然后在这个基础上,作者进行了封装。主要是用了Module类和继承了IFeature接口的类完成了依赖注入容器的封装。Module是用来管理feature和依赖的。Module我称......
  • asp.net core webapi 获取请求头token
    usingMicrosoft.AspNetCore.Mvc;usingMicrosoft.Extensions.Primitives;usingSystem.Collections.Generic;[ApiController][Route("[controller]")]publicclassMyController:ControllerBase{[HttpGet]publicIActionResultGet(){......
  • 基于ASP.NET+SQLServer的美妆网站的设计与实现
    ASP.NETMVC美妆商城项目文档计算机毕业设计案例C#社团软件CS基于Java的商品评价系统Java北方民族大学停车场管理系统PHP教学管理系统基于Java的报考指南微信小程序基于MVC的高校学生成果管理系统的设计与实现C#社团软件CSJava鲜花购物商城基于PHP的家居交流设计......