You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 04:35:10