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.
相关产品推荐
相关产品推荐

