ASP.NET CORE SIGNALR消息推送及在线聊天

话不多说,上代码

1、首先nuget引用Microsoft.AspNetCore.SignalR包

2、在Startup文件ConfigureServices加入services.AddSignalR();和跨域的代码,如下:

public IServiceProvider ConfigureServices(IServiceCollection services){
            //消息推送
            services.AddSignalR();
            //跨域 发布正式环境需要设置访问主机限制
            services.AddCors(options =>{
                options.AddPolicy("CorsPolicy", builder =>{
                    builder.SetIsOriginAllowed(origin => true).AllowAnyHeader().AllowAnyMethod().AllowCredentials();
                });
            });
            .........
        }

3、Configure里面(一个跨域和一个路由):

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env){
            if (env.IsDevelopment()){
                app.UseDeveloperExceptionPage();
            }
            //跨域
            app.UseCors("CorsPolicy");
            //添加SignalR路由配置代码,路由指向自定义类MessageHub
            app.UseSignalR(routes => {
                routes.MapHub<MessageHub>("/MessageHub");//直接路由到下面消息处理类
            });
            。。。。。
        }

4、建立一个消息处理类

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using CriticalMass.C2C.Model;
using Microsoft.AspNetCore.SignalR;
namespace CriticalMass.C2C.API.Extend
{
    [AllowCrossSiteJson]
    public class MessageHub:Hub
    {
        public static List<ConnectionSession> UserList = new List<ConnectionSession> { };
        //发送消息--发送给所有连接的客户端
        public Task SendMessage(string msg){
            return Clients.All.SendAsync("ReceiveMessage", msg);
        }
        //发送消息--发送给指定用户
        public Task SendPrivateMessage(string connectionId, string message){
            return Clients.Client(connectionId).SendAsync("ReceiveMessage", message);
        }
        /// <summary>
        /// 客户端登录到服务器
        /// </summary>
        /// <param name="uid"></param>
        public Task SendLogin(int uid) {
            AjaxResult result = new AjaxResult();
            try{
                ConnectionSession cs = UserList.Find(a => a.Uid == uid);
                if (cs != null){
                    UserList.Remove(cs);
                }
                UserList.Add(new ConnectionSession{
                    Uid = uid,
                    ConnectionId = Context.ConnectionId
                });
                result.Msg = "ok";
            }
            catch (Exception ex) {
                result.Msg = ex.Message;
            }
            return Clients.Client(UserList.Find(a=>a.Uid==uid).ConnectionId).SendAsync("ReceiveLogin", result.ToJson());
        }
    }
    public class ConnectionSession { 
        public int Uid { get; set; }
        public string ConnectionId { get; set; }
    }
}

5、前端代码

<ul class="form-group" id="messagesListUl" style="margin-bottom:20px"></ul>
 <ul class="form-group" id="messagesListUl2" style="margin-bottom:20px"></ul>
    <div class="form-group">
      <label for="username">姓名:</label>
      <input type="text" class="form-control" id="username" name="username">
    </div>
    <div class="form-group">
      <label for="msgcontent">内容:</label>
      <textarea rows="5" cols="20" id="msgcontent" name="msgcontent" class="form-control"></textarea>
    </div>
    <input type="button" οnclick="btnSendMsg()" value="发送">
 
<script src="jquery.js"></script>
<script src="signalr.js"></script>
<script type="text/javascript">
    //创建连接对象connection
    const signalr_connection = new signalR.HubConnectionBuilder()
                .withUrl("http://localhost:65423/MessageHub")//这里是我们前面建的那个类的名字
                .configureLogging(signalR.LogLevel.Information)
                .build();
 
    //启动connection
    signalr_connection.start()
                        .then(function(){
                            console.log("连接成功");
                            //这里与服务器连接成功之后,就要执行登录
                            signalr_connection.invoke("SendLogin", 18/*我这里传入的是用户ID,登录服务器之后需要保存用户信息的*/).catch(err => console.error("发送失败:"+err.toString()));
                        }).catch(function(ex){
                            console.log("连接失败"+ex);
                            //SignalR JavaScript 客户端不会自动重新连接,必须编写代码将手动重新连接你的客户端
                            //setTimeout(() => start(), 5000);
                        });
 
    async function start() {
        try {
            await signalr_connection.start();
            console.log("connected");
        } catch (err) {
            console.log(err);
            setTimeout(() => start(), 5000);
        }
    };
 
    signalr_connection.onclose(async () => {
        start();
    });
    
    signalr_connection.on("ReceiveChartMessage", function(data) {
        var msgObj = JSON.parse(data);//json串转对象
        console.log(JSON.stringify(msgObj));
        const li = document.createElement("li");
        li.textContent=JSON.stringify(msgObj);
        document.getElementById("messagesListUl2").appendChild(li);
    });
 
    
    //绑定事件("ReceiveMessage"和服务器端的SendMessage方法中的第一个参数一致)
    signalr_connection.on("ReceiveMessage", function(data) {
        var msgObj = JSON.parse(data);//json串转对象
        const li = document.createElement("li");
        li.textContent = msgObj.name + " : " + msgObj.message;
        document.getElementById("messagesListUl").appendChild(li);
    });
    
    //接受登录成功的消息
   signalr_connection.on("ReceiveLogin", function(data) {
        var msgObj = JSON.parse(data);//json串转对象
        console.log(JSON.stringify(msgObj));
        if(msgObj.Msg=="ok"){
        alert("登录成功");
        }
        else{
        alert(msgObj.Msg);
        }
    });
 
    //发送消息
    function btnSendMsg(){
        var username = $.trim($("#username").val());
        var msgcontent = $.trim($("#msgcontent").val());
        var msgObj={};
        msgObj.name=username;
        msgObj.message=msgcontent;
        var jsonstr=JSON.stringify(msgObj);//对象转json串
        console.log(jsonstr);
        signalr_connection.invoke("SendMessage", jsonstr).catch(err => console.error("发送失败:"+err.toString()));
    }
</script>


说两个方法:

signalr_connection.invoke调用后台服务
signalr_connection.on 前端页面监听后台方法调用
这个前端跟后台之间的相互调用有点蛋疼,耐着性子多看几遍就会明白,他娘的就跟RPC一样

6、后台消息推送实现
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using CriticalMass.C2C.Model;
using CriticalMass.C2C.IRepository;
using CriticalMass.C2C.Utility;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Caching.Memory;
using CriticalMass.C2C.API.Extend;
using Microsoft.AspNetCore.SignalR;

namespace CriticalMass.C2C.API.Controllers
{
    [TokenCheck]
    public class AdmChartController : BaseController{
        
        private readonly IHubContext<MessageHub> myHub;
        //构造函数注入MessageHub
        public AdmChartController(IHubContext<MessageHub> _myHub) {
            myHub = _myHub;
        }

        public string AuditChart([FromBody] dynamic parameModel) {
            AjaxResult result = new AjaxResult();
            try{
                string Ids = parameModel.ids;
                var ChartSrv = HttpContext.RequestServices.GetService<Itproduct_chart_detailsRepository>();
                var SessionSrv = HttpContext.RequestServices.GetService<Itproduct_chat_sessionRepository>();
                List<Model.tproduct_chart_details> lt = ChartSrv.GetList($"id in({Ids})");
                List<int> lt_status = lt.Map(a => (int)a.status).Distinct().ToList<int>();
                if (lt_status.Count > 1 || lt_status[0] != 0){
                    throw new Exception("状态不正确.");
                }
                ChartSrv.Update("status=1", $"id in({Ids})");
                List<dynamic> lt_msg = new List<dynamic>();
                Ids.Split(',').Each(a=> {
                    int uid = 0;
                    int to_uid = 0;
                    Model.tproduct_chart_details d = ChartSrv.GetModel(a.ToInt32());
                    Model.tproduct_chat_session s = SessionSrv.GetModel((int)d.session_id);
                    uid = (int)d.uid;
                    if (uid == s.session_call){
                        to_uid = (int)s.session_listen;
                    }
                    else {
                        to_uid = (int)s.session_call;
                    }
                    var obj = new { 
                        session_id=s.id,
                        uid= uid,
                        to_uid= to_uid,
                        msg=d.msg
                    };
                    lt_msg.Add(obj);
                });
                List<dynamic> list=lt_msg.Map(a => a.to_uid).Distinct().Map(b=> {
                    return new {
                        to_uid = b,
                        sessions = lt_msg.Filter(c=>c.to_uid == b).Map(f=>f.session_id).Distinct().Map(g=> {
                            return new {
                                session_id=g,
                                msg_lt= lt_msg.Filter(h=>h.to_uid==b && h.session_id==g).Map(j=> {
                                    return new {
                                        uid_send=j.uid,
                                        msg=j.msg
                                    };
                                })
                            };
                        })
                    };
                }).ToList<dynamic>();
                SendMsg(list);
                result.Msg = "ok";
            }
            catch (Exception ex) {
                result.Msg = ex.Message;
            }
            return result.ToJson();
        }

        /// <summary>
        /// 向客户端推送及时消息
        /// </summary>
        /// <param name="uid"></param>
        /// <param name="to_uid"></param>
        /// <param name="json"></param>
        public async Task SendMsg(List<dynamic> lt) {
            var task = Task.Run(()=> {
                lt.Each(a => {
                    int to_uid = a.to_uid;
                    object obj = a.sessions;
                    try{
                        ConnectionSession cs = MessageHub.UserList.Find(a => a.Uid == to_uid);
                        //在线
                        if (cs != null){
                            myHub.Clients.Client(cs.ConnectionId).SendAsync("ReceiveChartMessage", obj.ToJson());
                        }
                    }
                    catch { }
                });
            });
            await task;
        }
    }
}

注意

ConnectionSession cs = MessageHub.UserList.Find(a => a.Uid == to_uid);这一句

在MessageHub类定义了一个UserList用户信息全局静态数组变量,用户登陆后就会把用户信息更新到这个数据组

MessageHub.UserList.Find(a => a.Uid == to_uid)

这里我是通过用户ID在数组找到用户信息的,然后就可以拿到ConnectionId,拿到ConnectionId之后就可以给客户端发送通知了,发送pong到客户端ReceiveChartMessage这个方法(前面js中客户端已经对这个方法监听了),并带上参数即可

7、在线聊天原理差不多,服务器充当转发器即可

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值