IGeekFan.AspNetCore.SignalR.FreeRedis
SignalR 的 Redis Backplane,支持多节点实时消息广播。
功能概览
| 功能 | 说明 |
|---|---|
| 消息广播 | 多节点实时消息同步 |
| WebSocket 扩展 | 支持横向扩展 |
| Redis Backplane | 基于 FreeRedis 的消息中继 |
安装
dotnet add package IGeekFan.AspNetCore.SignalR.FreeRedis
快速开始
场景:即时聊天系统
1. 配置 Redis
{
"ConnectionStrings": {
"Redis": "127.0.0.1:6379,password=***,defaultDatabase=1"
}
}
2. 注册服务
using FreeRedis;
using IGeekFan.AspNetCore.SignalR.FreeRedis;
var builder = WebApplication.CreateBuilder(args);
// 注册 Redis 客户端
var redis = new RedisClient(builder.Configuration.GetConnectionString("Redis"));
builder.Services.AddSingleton(redis);
// 注册 SignalR + Redis Backplane
builder.Services
.AddSignalR()
.AddFreeRedis(builder.Configuration.GetConnectionString("Redis"));
var app = builder.Build();
app.MapHub<ChatHub>("/hubs/chat");
app.Run();
3. 创建 Hub
public class ChatHub : Hub
{
public async Task SendMessage(string user, string message)
{
await Clients.All.SendAsync("ReceiveMessage", user, message);
}
public async Task SendToGroup(string group, string message)
{
await Clients.Group(group).SendAsync("ReceiveMessage", message);
}
public async Task JoinGroup(string group)
{
await Groups.AddToGroupAsync(Context.ConnectionId, group);
await Clients.Group(group).SendAsync("SystemMessage", $"{Context.User.Identity.Name} 加入了群组");
}
public async Task LeaveGroup(string group)
{
await Groups.RemoveFromGroupAsync(Context.ConnectionId, group);
await Clients.Group(group).SendAsync("SystemMessage", $"{Context.User.Identity.Name} 离开了群组");
}
}
场景:实时通知系统
public class NotificationHub : Hub
{
private readonly INotificationService _notificationService;
public NotificationHub(INotificationService notificationService)
{
_notificationService = notificationService;
}
public async Task SendNotification(string userId, string title, string message)
{
// 发送给特定用户
await Clients.User(userId).SendAsync("ReceiveNotification", new
{
Title = title,
Message = message,
Timestamp = DateTime.Now
});
}
public async Task BroadcastNotification(string title, string message)
{
// 广播给所有连接的客户端
await Clients.All.SendAsync("ReceiveNotification", new
{
Title = title,
Message = message,
Timestamp = DateTime.Now
});
}
}
高级用法
客户端分组
// 加入组
await Groups.AddToGroupAsync(Context.ConnectionId, "admins");
// 离开组
await Groups.RemoveFromGroupAsync(Context.ConnectionId, "admins");
// 向组内发送消息
await Clients.Group("admins").SendAsync("ReceiveMessage", "Admin only message");
用户特定消息
// 向特定用户发送消息
await Clients.User("user-id-123").SendAsync("ReceiveMessage", "Hello!");
// 向特定连接发送消息
await Clients.Client("connection-id-456").SendAsync("ReceiveMessage", "Hello!");
连接生命周期
public class ConnectionHub : Hub
{
public override async Task OnConnectedAsync()
{
// 客户端连接时
await Clients.All.SendAsync("SystemMessage", $"{Context.User.Identity.Name} 已上线");
await base.OnConnectedAsync();
}
public override async Task OnDisconnectedAsync(Exception? exception)
{
// 客户端断开时
await Clients.All.SendAsync("SystemMessage", $"{Context.User.Identity.Name} 已离线");
await base.OnDisconnectedAsync(exception);
}
}
前端集成
JavaScript 客户端
import * as signalR from "@microsoft/signalr";
const connection = new signalR.HubConnectionBuilder()
.withUrl("/hubs/chat")
.withAutomaticReconnect()
.configureLogging(signalR.LogLevel.Information)
.build();
// 监听消息
connection.on("ReceiveMessage", (user, message) => {
console.log(`${user}: ${message}`);
});
// 启动连接
connection.start().catch(err => console.error(err));
// 发送消息
connection.invoke("SendMessage", "User1", "Hello everyone!");
TypeScript 客户端
import { HubConnectionBuilder, LogLevel } from "@microsoft/signalr";
interface Notification {
Title: string;
Message: string;
Timestamp: Date;
}
class SignalRService {
private connection: signalR.HubConnection;
constructor() {
this.connection = new HubConnectionBuilder()
.withUrl("/hubs/notification")
.withAutomaticReconnect()
.configureLogging(LogLevel.Information)
.build();
}
async start(): Promise<void> {
await this.connection.start();
}
onNotification(callback: (notification: Notification) => void): void {
this.connection.on("ReceiveNotification", callback);
}
async sendNotification(userId: string, title: string, message: string): Promise<void> {
await this.connection.invoke("SendNotification", userId, title, message);
}
}
运维建议
| 建议 | 说明 |
|---|---|
| 独立 Redis DB | 实时业务分配独立 Redis DB |
| 监控连接数 | 关注 WebSocket 连接数 |
| 监控广播延迟 | 监控消息广播延迟 |
| 配置超时 | 配置连接超时和重试策略 |
| 使用 TLS | 生产环境启用 TLS 加密 |
故障排查
| 问题 | 解决方案 |
|---|---|
| 连接失败 | 检查 Redis 连接字符串 |
| 消息丢失 | 检查 Redis 持久化配置 |
| 性能问题 | 检查 Redis 内存和连接数 |
| 认证失败 | 检查 SignalR 认证配置 |
相关文档
- DataProtection.FreeRedis - 密钥持久化
- Core - 基础包
- 包能力矩阵