SignalR 是一个强大的实时通讯库,在 .NET Core 中可以用来构建实时的、交互式的应用程序。本文将深入探讨 SignalR 的高级特性,包括用户组、连接/断开事件、强类型 Hub、自定义消息协议以及实时数据推送等应用场景。我们将通过具体示例来演示这些高级功能的实现。
1. 用户组和广播
1.1 用户组
SignalR 允许将客户端分组,向特定组发送消息。例如,创建一个聊天室应用,其中用户可以加入特定的聊天组,只接收组内的消息。
创建和管理用户组
using Microsoft.AspNetCore.SignalR;
using System.Threading.Tasks;
public class ChatHub : Hub
{
// 将用户添加到指定的用户组
public async Task JoinGroup(string groupName)
{
await Groups.AddToGroupAsync(Context.ConnectionId, groupName);
}
// 将用户从指定的用户组中移除
public async Task LeaveGroup(string groupName)
{
await Groups.RemoveFromGroupAsync(Context.ConnectionId, groupName);
}
// 向指定的用户组发送消息
public async Task SendMessageToGroup(string groupName, string message)
{
await Clients.Group(groupName).SendAsync("ReceiveMessage", message);
}
}
- JoinGroup 方法将当前连接的客户端添加到指定的用户组。
- LeaveGroup 方法将客户端从用户组中移除。
- SendMessageToGroup 方法向指定的用户组发送消息。
1.2 广播
如果你需要向所有连接的客户端发送消息,可以使用 Clients.All:
public class BroadcastHub : Hub
{
// 向所有连接的客户端广播消息
public async Task BroadcastMessage(string message)
{
await Clients.All.SendAsync("ReceiveMessage", message);
}
}
- BroadcastMessage 方法将消息发送到所有连接的客户端。
2. 连接和断开事件
SignalR 允许你处理客户端连接和断开事件,以执行自定义逻辑。
2.1 连接事件
在 Hub 类中重写 OnConnectedAsync 方法:
public class ConnectionHub : Hub
{
public override async Task OnConnectedAsync()
{
// 连接时的处理逻辑,例如记录连接信息
await Clients.Caller.SendAsync("ReceiveMessage", "Connected successfully!");
await base.OnConnectedAsync();
}
}
- OnConnectedAsync 方法在客户端连接到 Hub 时被调用。
2.2 断开事件
在 Hub 类中重写 OnDisconnectedAsync 方法:
public class ConnectionHub : Hub
{
public override async Task OnDisconnectedAsync(Exception exception)
{
// 断开连接时的处理逻辑,例如清理资源
await Clients.All.SendAsync("ReceiveMessage", "A user has disconnected.");
await base.OnDisconnectedAsync(exception);
}
}
- OnDisconnectedAsync 方法在客户端断开连接时被调用。
3. 强类型 Hub
使用强类型 Hub 可以为 Hub 方法提供类型安全和 IntelliSense 支持。
3.1 定义 Hub 接口
public interface IChatHub
{
Task SendMessage(string user, string message);
}
- 定义一个接口 IChatHub 来描述 Hub 的方法。
3.2 实现 Hub 接口
public class ChatHub : Hub<IChatHub>
{
public async Task SendMessage(string user, string message)
{
// 将消息发送到所有连接的客户端
await Clients.All.SendAsync("ReceiveMessage", user, message);
}
}
- 在 ChatHub 中实现 IChatHub 接口,提供强类型支持。
4. 自定义消息协议
SignalR 允许使用自定义消息协议来处理消息的序列化和反序列化。
4.1 自定义消息传输格式
public void ConfigureServices(IServiceCollection services)
{
services.AddSignalR().AddJsonProtocol(options =>
{
// 配置 JSON 序列化设置
options.PayloadSerializerOptions.PropertyNamingPolicy = null;
});
}
- 配置 SignalR 使用 JSON 序列化,并设置序列化选项。
4.2 自定义消息协议
可以实现 IHubProtocol 接口来创建自定义协议。以下是一个简单的示例:
using Microsoft.AspNetCore.SignalR.Protocol;
using System;
using System.IO;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
public class CustomProtocol : IHubProtocol
{
// 协议名称
public string Name => "custom";
// 传输格式,支持文本格式
public TransferFormat TransferFormat => TransferFormat.Text;
// 将消息序列化为自定义格式并写入流
public void WriteMessage(HubMessage message, Stream output)
{
// 将消息序列化为 JSON 字符串
var json = JsonSerializer.Serialize(message);
var buffer = Encoding.UTF8.GetBytes(json);
// 写入流
output.Write(buffer, 0, buffer.Length);
}
// 从流中读取消息并反序列化
public async Task<HubMessage> ReadMessageAsync(Stream input, System.Threading.CancellationToken cancellationToken = default)
{
using (var reader = new StreamReader(input, Encoding.UTF8))
{
// 读取 JSON 字符串
var json = await reader.ReadToEndAsync();
// 反序列化 JSON 字符串为 HubMessage
var message = JsonSerializer.Deserialize<HubMessage>(json);
return message;
}
}
}
- 创建自定义协议以满足特定的消息传输需求。
5. 实时数据推送
SignalR 适用于实时数据推送,例如实时股票行情、游戏状态更新等。
5.1 实时数据推送示例
假设你有一个股票行情应用,使用 SignalR 实时推送股票价格:
public class StockHub : Hub
{
public async Task SendStockPrice(string stockSymbol, decimal price)
{
// 向所有连接的客户端推送股票价格
await Clients.All.SendAsync("ReceiveStockPrice", stockSymbol, price);
}
}
- SendStockPrice 方法向所有客户端推送股票价格。
5.2 客户端处理数据
在前端页面中处理股票价格更新:
<!DOCTYPE html>
<html>
<head>
<title>Real-time Stock Prices</title>
</head>
<body>
<h1>Real-time Stock Prices</h1>
<div id="stockPrices"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/microsoft-signalr/6.0.0/signalr.min.js"></script>
<script>
const connection = new signalR.HubConnectionBuilder()
.withUrl("/stockHub")
.build();
// 处理接收到的股票价格
connection.on("ReceiveStockPrice", (stockSymbol, price) => {
const stockElement = document.createElement("div");
stockElement.textContent = `${stockSymbol}: $${price}`;
document.getElementById("stockPrices").appendChild(stockElement);
});
connection.start().catch(err => console.error(err.toString()));
</script>
</body>
</html>
- 在客户端,使用 SignalR 处理实时更新并将股票价格显示在页面上。
总结
SignalR 是一个功能强大的实时通讯库,在 .NET Core 中可以实现各种高级功能,包括用户组、广播、连接/断开事件、强类型 Hub、自定义消息协议以及实时数据推送。通过掌握这些高级特性,你可以构建出更加复杂和高效的实时应用程序。如果你有任何问题或需要进一步的帮助,请随时告诉我!