asp.net core 使用SignalR推送消息--【简单在线聊天功能】 以及 【推送消息给指定用户】

asp.net core 使用SignalR推送消息,本篇文章实现两个功能:1、简单在线聊天;2、推送消息给指定用户。

一、使用SignalR前准备工作:

1、使用Visual Studio Code 创建mvc项目

2、mvc项目添加Microsoft.AspNetCore.SignalR引用

3、下载signalr.js,放在wwwroot文件下任意位置

4、自定义类继承Hub,如下:

using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.SignalR;
using web.Model;

namespace web.Core
{
    public class MyHub : Hub
    { 
        //发送消息--发送给所有连接的客户端
        public Task SendMessage(string msg)
        {
            return Clients.All.SendAsync("ReceiveMessage", msg);
        }

        //发送消息--发送给指定用户
        public Task SendPrivateMessage(string userId, string message)
        {
            return Clients.User(userId).SendAsync("ReceiveMessage", message);
        }
    }
}

4、mvc项目配置 SignalR 服务、设置 SignalR 路由

在Startup.cs中的ConfigureServices方法添加代码

services.AddSignalR();

在Startup.cs中的Configure方法添加SignalR路由配置代码,路由指向自定义类MyHub,如下:

app.UseSignalR(routes=>{
   routes.MapHub<MyHub>("/MyHub");
});

5、客户端js中创建连接、启动连接代码,如下:

//创建连接对象connection
const signalr_connection = new signalR.HubConnectionBuilder()
            .withUrl("/MyHub")
            .configureLogging(signalR.LogLevel.Information)
            .build();

//启动connection
signalr_connection.start()
                    .then(function(){
                        console.log("连接成功");
                    }).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);
    }
};

这里准备工作差不多了。

二、简单在线聊天功能:

1、在HomeController 创建一个Action,如下:

public IActionResult Chat()
{
   return View();
}

html代码如下:

<ul class="form-group" id="messagesListUl" style="margin-bottom:20px"></ul>

<form>
    <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" onclick="btnSendMsg()" value="发送">
</form>

<script src="~/lib/jquery/dist/jquery.js"></script>
<script src="~/lib/signalr/dist/signalr.js"></script>
<script type="text/javascript">
    //创建连接对象connection
    const signalr_connection = new signalR.HubConnectionBuilder()
                .withUrl("/MyHub")
                .configureLogging(signalR.LogLevel.Information)
                .build();

    //启动connection
    signalr_connection.start()
                        .then(function(){
                            console.log("连接成功");
                        }).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();
    });

    
    //绑定事件("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);
    });

    //发送消息
    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>

说明:

a、signalr_connection.on() 绑定事件时,第一个参数对应MyHub类中的SendMessage方法中“Clients.All.SendAsync("ReceiveMessage", msg)”的第一个参数。

b、signalr_connection.invoke()发送消息时,第一个参数对应MyHub类中的SendMessage方法名。

效果如下:

 

三、推送消息给指定用户:

1、SignalR推送消息到指定用户(也可以时组)时,默认情况下,使用 SignalR的SignalRClaimTypes.NameIdentifier与用户标识符相关联,所以这里使用自带授权Authorize登陆(记得Startup中配置Authorize),把用户id保存在NameIdentifier中,登陆代码如下:

[HttpPost]
        public async Task<JsonResult> LoginPost()
        {
            var username = Request.Form["username"];
            var userpwd = Request.Form["userpwd"];            

            //本demo没连接数据库,就不做用户验证了,用户id就用Guid生成了
            
            //登陆授权
            string userId=Guid.NewGuid().ToString().Replace("-","");
            var claims =new List<Claim>()
            {
                new Claim(ClaimTypes.Name,username),   //储存用户name
                new Claim(ClaimTypes.NameIdentifier,userId)  //储存用户id
            };

            var indentity = new ClaimsIdentity(claims,"formlogin");
            var principal = new ClaimsPrincipal(indentity);

            await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme,principal);

            //验证是否授权成功
            if (principal.Identity.IsAuthenticated)
            {
                return Json(new { code = "success", msg = "登陆成功" });
            }
            else
                return Json(new { code = "failed", msg = "登陆失败" });
        }

上述代码使用new Claim(ClaimTypes.NameIdentifier,userId) 储存用户id

2、发送消息Action代码

首先在HomeController中注入IHubContext实例:

private readonly IHubContext<MyHub> myHub;
public HomeController(IHubContext<MyHub> _myHub)
{
    myHub=_myHub;
} 

然后发送消息Action代码:

[Authorize,HttpPost]
public async Task<IActionResult> PostData()
{
     var userId = Request.Form["userid"];
     var message = Request.Form["message"];
            
     if(!string.IsNullOrWhiteSpace(userId))
         await myHub.Clients.User(userId).SendAsync("ReceiveMessage", new {message=message});
            
     return Json(new { code = "success", msg = "发送成功" });
}

3、接受消息页面和上面聊天功能页面的js代码类似。

4、我用360和谷歌浏览器分别用两个用户登陆,效果如下:

UserID:3300127337da407ca311c89ca5b1abdc是360浏览器登陆时Guid生成的用户id,用另一个用户在谷歌浏览器登陆,发送消息指定用户id即可。

 

注:我是实现功能后写的博客,所以博客的逻辑符合自己的思路,对于旁人可能会有些混乱,所以附上源码

1、https://gitee.com/qk2017/NetCoreSignalRDemo

2、https://download.csdn.net/download/coderk2014/11072034

已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 书香水墨 设计师:CSDN官方博客 返回首页