跳到主要内容

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 认证配置

相关文档​