Blazor Server中如何跨多页面共享SignalR HubConnection?
复用Blazor Server的SignalR连接解决方案
1. 创建全局SignalR连接服务
新建一个ChatHubService类,作为单例管理SignalR连接,通过自定义事件传递消息,避免直接耦合页面方法:
using Microsoft.AspNetCore.SignalR.Client; using System; public class ChatHubService { private readonly HubConnection _hubConnection; // 定义消息接收事件,供页面组件订阅 public event Action<string, string>? MessageReceived; public ChatHubService() { // 初始化连接,替换为你的Hub地址 _hubConnection = new HubConnectionBuilder() .WithUrl("/chatHub") .Build(); // 绑定SignalR的Broadcast方法,触发自定义事件传递消息 _hubConnection.On<string, string>("Broadcast", (user, message) => { MessageReceived?.Invoke(user, message); }); } // 确保连接处于活跃状态 public async Task StartConnectionAsync() { if (_hubConnection.State != HubConnectionState.Connected) { await _hubConnection.StartAsync(); } } // 加入指定聊天室 public async Task JoinRoomAsync(int roomId) { await StartConnectionAsync(); await _hubConnection.SendAsync("JoinRoom", roomId); } // 离开指定聊天室 public async Task LeaveRoomAsync(int roomId) { if (_hubConnection.State == HubConnectionState.Connected) { await _hubConnection.SendAsync("LeaveRoom", roomId); } } // 发送消息到指定房间 public async Task SendMessageAsync(string user, string message, int roomId) { await _hubConnection.SendAsync("SendMessage", user, message, roomId); } // 应用关闭时释放连接 public async ValueTask DisposeAsync() { await _hubConnection.DisposeAsync(); } }
2. 注册单例服务
在Program.cs中将服务注册为单例,确保整个应用只有一个SignalR连接实例:
builder.Services.AddSingleton<ChatHubService>(); // 可选:让服务实现IHostedService,自动管理连接生命周期 // builder.Services.AddSingleton<IHostedService, ChatHubService>();
3. 在聊天页面组件中使用服务
修改你的Chat页面组件,注入服务并订阅事件,处理房间切换逻辑:
@page "/chat/{roomId:int}" @inject ChatHubService ChatHub @implements IDisposable <h3>聊天室 @RoomId</h3> <!-- 聊天UI和消息列表,保留原有界面逻辑即可 --> @code { [Parameter] public int RoomId { get; set; } private int _previousRoomId; protected override async Task OnInitializedAsync() { // 订阅消息接收事件,绑定页面内的处理方法 ChatHub.MessageReceived += BroadcastMessage; // 加入当前房间 await ChatHub.JoinRoomAsync(RoomId); _previousRoomId = RoomId; } protected override async Task OnParametersSetAsync() { // 房间ID变化时,离开旧房间并加入新房间 if (_previousRoomId != RoomId) { await ChatHub.LeaveRoomAsync(_previousRoomId); await ChatHub.JoinRoomAsync(RoomId); _previousRoomId = RoomId; } } // 原页面内的消息处理逻辑 private void BroadcastMessage(string user, string message) { // 这里添加消息展示逻辑,比如更新消息列表 // Messages.Add($"{user}: {message}"); StateHasChanged(); } // 发送消息的方法,调用服务接口 private async Task SendMessage() { await ChatHub.SendMessageAsync(UserName, InputMessage, RoomId); InputMessage = string.Empty; } public void Dispose() { // 组件销毁时取消事件订阅,避免内存泄漏 ChatHub.MessageReceived -= BroadcastMessage; } }
关键说明
- 单例服务确保整个应用生命周期内只有一个SignalR连接,切换房间无需重新创建连接,彻底解决代理延迟问题。
- 通过自定义
MessageReceived事件实现服务与页面的解耦,页面只需订阅事件就能处理消息,无需直接绑定Hub的方法。 - 房间切换时调用
LeaveRoom和JoinRoom接口,复用现有连接完成房间切换逻辑,全程无页面刷新。
内容的提问来源于stack exchange,提问作者ByteBlaze
相关产品推荐
相关产品推荐

