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

Blazor Server自定义SignalR Hub配置URL未被使用的问题

问题描述

在.NET 9中创建默认Blazor Web应用项目,添加了用于客户端间发送通知的SignalR Hub。当某个会话递增/counter页面数值时,所有会话都会收到通知并更新显示,功能完全正常,但浏览器开发者工具中看不到配置的Hub URL(/counter-notifications)对应的连接,只有指向/_blazor的标准Blazor Server WebSocket连接。是否默认Blazor WebSocket连接被复用给自定义SignalR了?

相关代码

Counter.razor

<PageTitle>Counter</PageTitle>

<h1>Counter</h1>

<p role="status">Current count: @currentCount</p>

<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>

@code {
    private int currentCount = 0;
    private HubConnection _hubConnection;
    
    public async ValueTask DisposeAsync()
    {
        await _hubConnection.DisposeAsync();
    }
    
    protected override async Task OnInitializedAsync()
    {
        _hubConnection = new HubConnectionBuilder()
            .WithUrl(NavigationManager.ToAbsoluteUri(CounterHub.HubUrl))
            .Build();
        
        _hubConnection.On<CounterNotification>(CounterHub.CounterUpdatedMethod, HandleCounterUpdated);
        await _hubConnection.StartAsync();
    }

    private void HandleCounterUpdated(CounterNotification notification)
    {
        currentCount = notification.Counter;
        InvokeAsync(StateHasChanged);
    }

    private async Task IncrementCount()
    {
        await CounterHubContext.Clients.All.SendAsync(CounterHub.CounterUpdatedMethod, new CounterNotification(currentCount + 1));
    }
}

CounterHub.cs

public class CounterHub : Hub
{
    public const string HubUrl = "/counter-notifications";
    public const string CounterUpdatedMethod = "CounterUpdated";

    public override Task OnConnectedAsync()
    {
        Console.WriteLine("{0} connected", Context.ConnectionId);
        return base.OnConnectedAsync();
    }

    public override async Task OnDisconnectedAsync(Exception? e)
    {
        Console.WriteLine("{0} disconnected", Context.ConnectionId);
        await base.OnDisconnectedAsync(e);
    }
}

CounterNotification.cs

public record CounterNotification(int Counter)
{
    public CounterNotification() : this(0) { }
}

Program.cs 配置

builder.Services.AddSignalR();

builder.Services.AddResponseCompression(opts =>
{
    opts.MimeTypes = ResponseCompressionDefaults.MimeTypes.Concat(
        ["application/octet-stream"]);
});

app.UseResponseCompression();

app.MapHub<CounterHub>(CounterHub.HubUrl);

浏览器连接截图

Firefox开发者工具仅显示一个WebSocket连接

解答

没错,你的自定义SignalR Hub确实复用了Blazor Server默认的/_blazor WebSocket连接,这是.NET 8及以后版本Blazor Server的默认行为——SignalR Hub共享连接复用。

核心原因

  1. 自动复用机制:Blazor Server启动时会创建主SignalR连接(/_blazor)用于组件交互和渲染更新。在.NET 8+中,所有同域的SignalR Hub都会自动复用这个已建立的WebSocket连接,无需创建新连接。
  2. 性能优化考量:这种设计减少了浏览器的连接数开销,避免多WebSocket连接带来的资源消耗,同时简化了连接的生命周期管理。

验证方法

  • 查看CounterHub的OnConnectedAsync日志:页面加载时会打印新的ConnectionId,但浏览器仅显示一个/_blazor连接,说明Hub已通过复用连接完成注册。
  • 开启SignalR客户端日志:在HubConnectionBuilder中添加ConfigureLogging(logging => logging.AddConsole()),可以看到连接复用的详细日志。

如何禁用连接复用(可选)

如果确实需要独立的WebSocket连接,可以在创建HubConnection时显式禁用复用:

_hubConnection = new HubConnectionBuilder()
    .WithUrl(NavigationManager.ToAbsoluteUri(CounterHub.HubUrl), options =>
    {
        // 禁用自动重连(可选,根据需求调整)
        options.DisableAutomaticReconnect();
        // 关键:添加自定义请求头告知服务器不复用连接
        options.Headers.Add("X-SignalR-No-Reuse", "true");
    })
    .Build();

注意:除非有特殊业务需求,否则不建议禁用,会失去连接复用带来的性能优势。

内容的提问来源于stack exchange,提问作者orderlyfashion

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 11:50:21