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

posted @ 2025-02-16 15:10  getRainbow  阅读(172)  评论(0)    收藏  举报