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