1.服务端安装SignalR的Nuget包
dotnet add package Microsoft.AspNet.SignalR --version 2.4.3
2.接下来,创建一个ChatHub类,它是SignalR通信的核心:
using Microsoft.AspNetCore.SignalR;public class ChatHub : Hub
{public static Dictionary<string, string> user = new();public void Connect(string key){if (user.ContainsKey(key)) { user.Remove(key); }user.Add(key,Context.ConnectionId);Console.WriteLine("("+ DateTime.Now +")客户端:"+ key + "上线成功!");}public async Task HandMsg(Chat chat){chat.time = DateTime.Now;ChatHandlerService handler;switch ( (Command) chat.cmd){case Command.PRIVATE:handler = new PrivateServiceImpl();await handler.execute(chat,user,Context,Clients);break; case Command.LINERADIO:handler = new LineradioServiceImpl();await handler.execute(chat, user, Context, Clients);break;}}
}
-
这个是信息处理的提取ChatHandlerService
public interface ChatHandlerService
{Task execute(Chat chat,Dictionary<string, string> user,HubCallerContext context, IHubCallerClients clients);
}
-
这个是单聊的具体实现
public class PrivateServiceImpl : ChatHandlerService
{public Task execute(Chat chat, Dictionary<string, string> user, HubCallerContext context, IHubCallerClients clients){if (user.ContainsKey(chat.target!)){string target = user[chat.target!];clients.Client(target).SendAsync("receive", chat);return Task.CompletedTask;}chat.message = "好友不在线";clients.Client(context.ConnectionId).SendAsync("receive", chat);return Task.CompletedTask;}
}
-
这个是 通知全部在线的用户
public class LineradioServiceImpl : ChatHandlerService
{public async Task execute(Chat chat, Dictionary<string, string> user, HubCallerContext context, IHubCallerClients clients){await clients.All.SendAsync("receive", chat); }
}
-
指令枚举
public enum Command
{PRIVATE = 300,GROUP = 400,LINERADIO = 500
}
-
聊天模型
public class Chat
{public string userKey { get; set; } = null!;public string? target { get; set; }public string? message { get; set; }public int type { get; set; }public int cmd { get; set; }public DateTime time { get; set; }
}
提示:Connect是连接的实例方法,当客户端成功后在回调使用此方法,HandMsg是我的信息处理方法,其中你可以不用我的service和实现层,直接在ChatHub类中使用你传入的数据就可以了。
3.在Program中使用
builder.Services.AddSignalR();builder.Services.AddCors(options =>
{options.AddDefaultPolicy(builder =>{builder.WithOrigins("http://localhost").AllowAnyHeader().WithMethods("GET", "POST").AllowCredentials();});
});app.MapHub<ChatHub>("/chathub");
提示:注意需要配置跨域
4.编写客服端代码
<!DOCTYPE html>
<html lang="">
<head><title>SignalR</title><script src="https://cdnjs.cloudflare.com/ajax/libs/microsoft-signalr/8.0.0/signalr.min.js"></script><meta charset="utf-8" />
</head>
<style>input {border-radius: 12px;padding: 5px 5px;}.sendButton {width:200px;border-radius: 12px;background: #3F95FF;padding: 6px 0;border: none;color: white;}
</style>
<body><h1>SignalR</h1>
<div style="display: flex;gap: 12px;flex-direction: column"><div><label for="target">发送给:</label><input type="text" id="target" /></div><div><label for="msg">信息:</label><input type="text" id="msg" /></div><div><button type="button" id="sendButton" class="sendButton">发送</button></div>
</div>
<div><ul id="messagesList"></ul>
</div><script>/*** 获取URL中的查询参数值** @param {string} name - 查询参数名* @returns {string|null} - 查询参数值,如果不存在则返回null*/function getQueryParam(name) {const urlParams = new URLSearchParams(window.location.search);return urlParams.get(name);}/*** 初始化SignalR连接*/const connection = new signalR.HubConnectionBuilder().withUrl("https://localhost:7066/chathub").configureLogging(signalR.LogLevel.Information).build();/*** 监听服务器发送的消息** @param {object} res - 接收到的消息对象*/connection.on("receive", res => {const li = document.createElement("li");li.textContent = `${ res.userKey }: ${res.message}`;document.getElementById("messagesList").appendChild(li);});/*** 启动SignalR连接,并调用Connect方法向服务器发送连接请求*/connection.start().then(() => {connection.invoke("Connect", getQueryParam("key")).catch(err => console.error(err.toString()));}).catch(function (err) {return console.error(err.toString());});/*** 发送按钮点击事件处理函数** @param {Event} event - 事件对象*/document.getElementById("sendButton").addEventListener("click", event => {const target = document.getElementById("target").value;const message = document.getElementById("msg").value;let sendMessage = {userKey: getQueryParam("key"),target: target,cmd: 300,message: message};/*** 调用服务器HandMsg方法发送消息*/connection.invoke("HandMsg", sendMessage).then(res => {const li = document.createElement("li");li.textContent = `我: ${message}`;document.getElementById("messagesList").appendChild(li);document.getElementById("msg").value = "";}).catch(err => console.error(err.toString()));event.preventDefault();});
</script>
</body>
</html>
浏览器需要在后面跟上参数Key
http://localhost/?key=10086
5.完整代码地址
https://gitee.com/byte1026/signal-r.git