一个function里调用另一个function_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,我就是为了让前端和后端统一下。刚开始Hub我纠结了好久,不知道怎么用,最后我手动做了下,认为它只是为了方便前端和后端统一。

如果你只是简单的继承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,自己定义一个接口,提过方法InvokeMessage供前前端调用。

/// /// 客户端js调用方法/// public interface ISingalrClient    {Task InvokeMessage(Message sendMessage);    }public class SingalrService : Hub    {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 _hubContext;private ISingalrSvc _singalrSvc;public SingalrController(IHubContext hubContext, ISingalrSvc singalrSvc)  {      _hubContext = hubContext;      _singalrSvc = singalrSvc;  }/// /// 查询未处理数量/// /// ///   [HttpGet("{account}")]public async Task NewsCount(string account)  {      Message sendMessage = new Message();      sendMessage.Data = "11";//刚已经讲了,用户加载首页的时候已经把connectionid和account存入到了内存里面,现在再取用户相关的connectionID,如果直接调用Clinets.ALL就是给所有客户端发送消息      IReadOnlyList connectionIds = (IReadOnlyList)_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); }, }); });

原文地址:

https://www.cnblogs.com/MrHanBlog/p/11996689.html

bc8d1392e1e63731ff62def5de09c2cd.png

点击 【在看】与好友一起分享
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值