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

Blazor Server启动时SignalR为何连接8个服务器?

Blazor Server中SignalR出现多余服务器连接的问题

启动Blazor Server应用时,我发现SignalR服务里显示有8个服务器已连接,完全搞不懂为什么会这样。我的需求很明确:让MyRazorPage既能从自身也能从Azure Function收发SignalR消息,同时要避免创建这么多(多余的)服务器连接。

下面是我的代码、依赖注入服务注册及相关配置:

代码

MyRazorPage.razor

@inject IHubConnectionFactory HubConnectionFactory // 见下方HubConnectionFactory.cs

MyRazorPage.razor.cs

public sealed partial class MyRazorPage
{
    private HubConnection _hubConnection;
    
    public async ValueTask DisposeAsync()
    {
        if (_hubConnection is not null)
        {
            _hubConnection.Remove("MyMethodName");
            await _hubConnection.DisposeAsync();
        }
    }
    
    private async Task HandleHubMessageReceived(ResultDto result)
    {
        // 处理接收的结果
    }
    
    private async Task SendMessage()
    {
        // ... 
        await _hubConnection.SendAsync("MethodName", new ResultDto(Guid.Parse(CustomerId), ResultEnum.Success));        
    }
    
    protected override async Task OnInitializedAsync()
    {  
        _hubConnection = HubConnectionFactory.CreateHubConnection();
        await _hubConnection.StartAsync(CancellationToken);
        _hubConnection.On<ResultDto>("MyMethodName", HandleHubMessageReceived);
    }   
}

配置、服务注册及SignalR中间件

包引用

<PackageReference Include="Microsoft.Azure.SignalR" Version="1.24.0" />
<PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="8.0.1" />

appsettings.json

"Azure": {
   "SignalR": {
     "Enabled": "true",
     "ConnectionString": "Endpoint=URL;AccessKey=KEY;Version=1.0;"
   },
 "SIGNALR_REFRESH_BILLING_PAGE_URI": "https://localhost:44362/MyHub",
}

Startup.cs

public void ConfigureServices(IServiceCollection services)
{
    services.AddSignalR();
    services.AddSignalRHubConnection(config =>{
               config.ConnectionString = Configuration["SIGNALR_REFRESH_BILLING_PAGE_URI"] ?? 
               string.Empty;
               });
}

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    app.UseRequestLocalization(app.ApplicationServices.GetService<IOptions<RequestLocalizationOptions>>().Value);

    if (!env.IsProduction())
    {
        app.UseDeveloperExceptionPage();
        app.UseMigrationsEndPoint();
    }
    else
    {
        app.UseExceptionHandler("/Error");
        // 默认HSTS值为30天,生产环境可根据需要修改
        app.UseHsts();
    }
    
    app.UseHttpsRedirection();
    app.UseStaticFiles();

    app.UseRouting();

    app.UseAuthentication();
    app.UseAuthorization();
    
    app.UseCookiePolicy();
    
    app.UseEndpoints(endpoints =>
                     {
                         endpoints.MapControllers();
                         endpoints.MapBlazorHub();
                         endpoints.MapRazorPages();
                         endpoints.MapFallbackToPage("/_Host");
                         endpoints.MapHub<MyHub>($"/{MyHub.HubName}");
                     });
}

HubConnectionFactory.cs

public class HubConnectionFactory : IHubConnectionFactory
{
    private readonly SignalREndpointConfiguration _configuration;
    
    public HubConnectionFactory(IOptions<SignalREndpointConfiguration> configuration) => _configuration = configuration.Value;
    
    public HubConnection CreateHubConnection()
    {
        return new HubConnectionBuilder()
               .WithUrl(_configuration.ConnectionString)
               .Build();
    }  
}

MyHub.cs

public class MyHub : Hub
{
    public const string HubName = "MyHub";

    public async Task SendMessage(ResultDto dto)
    {
        await Clients.All.SendAsync("MyMethodName", dto);
    }
}

已尝试的方案(均未解决)

方案结果
移除appsettings.json中的Azure配置HandleHubMessageReceived不再被调用
在Startup.cs的ConfigureServices中添加services.AddCors(),并在Configure中添加app.UseCors(policy => policy.AllowAnyHeader().AllowAnyMethod().AllowAnyOrigin())无任何变化

问题分析与解决建议

1. 为什么会出现8个服务器连接?

你看到的“8个服务器连接”是Azure SignalR Service的默认连接池行为——SDK会自动建立多个连接到Azure SignalR的后端节点,用于实现负载均衡和高可用性,这是服务端层面的连接,并非客户端连接。

另外你的代码存在一个关键问题:MyRazorPage每次初始化都会新建一个HubConnection客户端连接。如果页面被多次渲染(比如路由切换后返回),会创建大量客户端连接,叠加Azure SignalR的服务端连接,就会出现连接数过多的情况。

2. 优化方案

(1)复用客户端HubConnection

不要每次页面初始化都新建连接,将HubConnection注册为单例服务,在应用内复用:

修改HubConnectionFactory实现单例连接逻辑:

public class HubConnectionFactory : IHubConnectionFactory
{
    private readonly SignalREndpointConfiguration _configuration;
    private HubConnection _hubConnection;
    private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1, 1);

    public HubConnectionFactory(IOptions<SignalREndpointConfiguration> configuration) => _configuration = configuration.Value;
    
    public async Task<HubConnection> GetOrCreateHubConnectionAsync(CancellationToken cancellationToken)
    {
        if (_hubConnection != null && _hubConnection.State == HubConnectionState.Connected)
        {
            return _hubConnection;
        }

        await _semaphore.WaitAsync(cancellationToken);
        try
        {
            if (_hubConnection != null)
            {
                await _hubConnection.DisposeAsync();
            }

            _hubConnection = new HubConnectionBuilder()
               .WithUrl(_configuration.ConnectionString)
               .Build();

            await _hubConnection.StartAsync(cancellationToken);
        }
        finally
        {
            _semaphore.Release();
        }

        return _hubConnection;
    }
}

在DI中注册为单例:

services.AddSingleton<IHubConnectionFactory, HubConnectionFactory>();

修改MyRazorPage的初始化逻辑:

protected override async Task OnInitializedAsync()
{  
    _hubConnection = await HubConnectionFactory.GetOrCreateHubConnectionAsync(CancellationToken);
    _hubConnection.On<ResultDto>("MyMethodName", HandleHubMessageReceived);
}
(2)统一Azure SignalR配置

你当前的配置存在混淆,既配置了Azure SignalR连接字符串,又使用本地Hub地址,需要统一:

  • 使用Azure SignalR Service时,在ConfigureServices中用AddAzureSignalR替代原生AddSignalR:
services.AddSignalR()
        .AddAzureSignalR(Configuration["Azure:SignalR:ConnectionString"]);
  • 客户端连接可直接使用相对路径(SDK会自动路由到Azure SignalR服务),无需硬编码本地地址。
(3)调整连接清理逻辑

页面销毁时仅移除自身注册的回调,不要销毁全局复用的连接:

public async ValueTask DisposeAsync()
{
    if (_hubConnection is not null)
    {
        _hubConnection.Remove("MyMethodName");
        // 不要调用DisposeAsync,连接为全局复用
    }
}

3. 验证效果

修改后,客户端连接数会大幅减少(每个用户对应少量连接),Azure SignalR的服务端连接数会保持在SDK自动管理的合理范围内。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 10:14:54