SignalR 服务端消息推送
概念
ASP.NET Core SignalR 是一种用于在应用程序中添加实时功能的库。它允许服务器和客户端之间的双向通信,使得服务器能够主动推送数据到客户端,而无需客户端轮询服务器。SignalR 常用于聊天应用、实时仪表板、通知系统等场景。
SignalR提供了用于创建服务器到客户端远程过程调用的API,这样即可通过服务器端的.NET Core代码调用客户端上的JavaScript函数,它主要通过hub(集线器)在客户端和服务器之间进行通信,所有连接到同一个hub上的程序都可以互相通信
在SignalR中提供了两个内置的hub协议,分别为基于JSON的文本协议和基于MessagePack的二进制协议
使用SignalR实现服务端推送
1. 添加SignalR客户端库
SignalR服务器库包含在ASP.NET Core中,但其客户端库不会自动包含在项目中,需要手动进行添加
2. 实现SignalR Hub类
Hub类位于Microsoft.AspNetCore.SignalR命名空间中,它主要用作处理SignalR中客户端到服务器通信的高级管道
在使用Hub类的属性时,可以使用Context.ConnectionId来获得当前调用方法的客户端唯一标识符;另外,Hub类的Clients属性返回一个IHubCallerClients接口对象,该对象提供了对连接到当前Hub的客户端进行筛选的成员
上面这些成员的返回值类型都是IClientProxy类型,该类型中定义了一个SendCoreAsync()方法(扩展方法为SendAsync()),用来向客户端发送消息
在项目中创建一个Hubs文件夹,并在其中创建一个ChatHub.cs类文件,该文件中定义ChatHub类,并继承自SignalR的Hub类,然后定义一个SendMessage()方法,用来调用Hub对象的Clients.All.SendAsync()方法向所有客户端发送消息。
using Microsoft.AspNetCore.SignalR;
namespace SignalRDemo.Hubs
{
public class ChatHub:Hub
{
public async Task SendMessage(string user, string message)
{
//拼接消息字符串
string msg = $"{user} {DateTime.Now}: {message}";
await Clients.All.SendAsync("ReceiveMessage", msg);
}
}
}
3. 配置SignalR Hub服务
//注册SignalR服务
builder.Services.AddSignalR();
//var app = builder.Build();
//启用SignalR中间件
app.MapHub<ChatHub>("/chathub");
4. 实现客户端页面
创建一个Chat.cshtm
@page
@model SignalRDemo.Pages.ChatModel
@{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.min.css" />
<title>聊天室</title>
</head>
<body>
<div class="container">
<div class="row p-1">
<div class="col-1">用户名:</div>
<div class="col-5">
<input type="text" id="userInput" />
</div>
</div>
<div class="row p-1">
<div class="col-1">消息:</div>
<div class="col-5">
<input type="text" class="w-100" id="messageInput" />
</div>
</div>
<div class="row p-1">
<div class="col-6 text-end">
<input type="button" id="sendButton" value="发送" />
</div>
</div>
<div class="row p-1">
<div class="col-6">
<hr />
</div>
</div>
<div class="row p-1">
<div class="col-6">
<ul id="messagesList"></ul>
</div>
</div>
</div>
</body>
<script src="~/lib/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
<script src="~/lib/microsoft-signalr/signalr.min.js"></script>
<script>
//创建从客户端到服务器的连接
let connection = new signalR.HubConnectionBuilder().withUrl("/chathub").build();
//禁用发送按钮
document.getElementById('sendButton').disabled = true;
//从SignalR Hub接收消息并将其添加到列表
connection.on("ReceiveMessage", function(msg) {
let li = document.createElement('li');
document.getElementById('messagesList').appendChild(li);
li.textContent = `${msg}`;
});
//建立连接时执行
connection.start().then(function() {
//设置发送按钮可用
document.getElementById('sendButton').disabled = false;
}).catch(function(err) {
return console.error("建立连接错误: ",err);
});
//为发送按钮添加click事件
document.getElementById('sendButton').addEventListener("click", function(event) {
let user = document.getElementById('userInput').value;
let message = document.getElementById('messageInput').value;
//发送消息
connection.invoke("SendMessage", user, message).catch(function() {
return console.error("发送消息错误: ",err);
});
//设置浏览器不执行与事件关联的默认动作
event.preventDefault();
})
</script>
</html>
5. 运行程序
打开两个浏览器访问 ip:端口/chat