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

.NET SignalR Hub持续被释放,服务端向客户端推送失败求助

SignalR Hub持续被释放导致服务端无法向客户端通信问题分析

问题现象

  • 配置.NET SignalR内部Hub,仅允许桌面应用连接
  • 客户端可正常向Hub发起调用,但Hub向客户端推送消息时提示「已释放」错误
  • Hub实例在连接建立后持续触发Dispose操作,客户端未收到断开事件且连接状态显示正常
  • Hub析构函数从未被调用

已排查信息

  • 仅发起1次连接请求,客户端连接状态显示正常
  • 核心异常点:Hub实例频繁被Dispose,导致服务端无法持有有效连接实例推送消息

服务端Hub配置代码

public void ConfigureServices(IServiceCollection services)
{
    services.AddGrpc();
    
    services.AddCors(o =>
    {
        o.AddDefaultPolicy(b =>
        {
            b.WithOrigins(TargetURL)
                .AllowCredentials()
                .AllowAnyHeader();
        });
    });

    services.AddHostedService<Worker>();

    services.AddSignalR(hubOptions =>
    {
        hubOptions.EnableDetailedErrors = true;
        hubOptions.ClientTimeoutInterval = TimeSpan.FromSeconds(100);
        hubOptions.KeepAliveInterval = TimeSpan.FromMinutes(100);
    });
}

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
        app.UseSwagger();
        app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "oiStockPusherSite v1"));
    }

    app.UseRouting();
    app.UseCors(PolicyName);

    app.UseEndpoints(endpoints =>
    {
        //endpoints.MapControllers(); 
        endpoints.MapHub<TradingServiceHub>("/orderITSignalR", options =>
        {
            options.Transports = HttpTransportType.LongPolling; // you may also need this
        });
    });            
}

客户端Hub激活代码

protected virtual bool PrepareTradeActivityHub(string TargetHub)
{            
    string TradeActivitySignalRURL = "";
    bool Res = false;

    lock (PreparingHub)
    {
        TradeActivitySignalRURL = Connection;

        if (!PrepareNewHub)
        {                   
            if (HubConnectionOld == null)
            {                        
                EventLog.WriteEntry("Support", string.Format("Prepare Trade Service Hub for {0}", TradeActivitySignalRURL), EventLogEntryType.Information);

                HubConnectionOld = new Microsoft.AspNet.SignalR.Client.HubConnection(TradeActivitySignalRURL);
                HubConnectionOld.Closed += TradingClientHubConnection_Closed;

                ClientHubProxy = HubConnectionOld.CreateHubProxy(TargetHub);

                Task<bool> Result = TradingClientHubConnection_Connect();
                Result.Wait();

                if (!Result.Result)
                {
                    EventLog.WriteEntry("Support", "Failed to start Trade Service Hub", EventLogEntryType.Error);

                    StopHubConnection();
                }
                else
                {
                    EventLog.WriteEntry("Support", "Connected to Trade Service Hub", EventLogEntryType.Error);
                    
                    Result = ClientHubProxy?.Invoke<bool>("Active");
                    if (Result != null)
                    {
                        Result.Wait();
                        Res = Result.Result;
                        CallCheckActivated();                                
                        HubConnected = true;
                    }
                    else
                        Res = false;
                }
            }
            else
            {
                EventLog.WriteEntry("Support", "Check if Hub still connectedHub", EventLogEntryType.Information);

                Res = true;
                if (ClientHubProxy != null)
                {
                    Task.Run(async () =>
                    {
                        if (ClientHubProxy != null)
                        {
                            EventLog.WriteEntry("Support", "Test calling Hub Active operation", EventLogEntryType.Information);

                            Res = await ClientHubProxy?.Invoke<bool>("Active");

                            if (Res)
                            {                                        
                                CallCheckActivated();
                                EventLog.WriteEntry("Support", "Successfully called Hub Active operation", EventLogEntryType.Information);
                            }
                            else
                            {
                                EventLog.WriteEntry("Support", "Problem calling Hub Active operation", EventLogEntryType.Error);
                            }
                        }
                    }
                    ).Wait();
                }
                else
                {
                    EventLog.WriteEntry("Support", "Hub not avaible - should be", EventLogEntryType.Error);
                }
            }
        }
        else
        {                    
            if (HubConnectionNew == null)
            {
                EventLog.WriteEntry("Support", string.Format("Prepare Trade Service Hub for {0}", TradeActivitySignalRURL), EventLogEntryType.Information);

                HubConnectionNew = new HubConnectionBuilder().WithUrl(TradeActivitySignalRURL).Build();
                HubConnectionNew.Closed += StockPusherHubDisconnect;
               var Connect = StockPusherHubConnection_Connect();
                Connect.Wait();

                EventLog.WriteEntry("Support", "Test calling Hub Active operation", EventLogEntryType.Information);

                var Response = HubConnectionNew.InvokeAsync<bool>("Active").Result;
                if (!Response)
                {
                    HubConnectionNew = null;
                    EventLog.WriteEntry("Support", "Problem calling Hub Active operation", EventLogEntryType.Error);
                    HubConnected = false;
                }
                else
                {
                    EventLog.WriteEntry("Support", "Successfully called Hub Active operation", EventLogEntryType.Information);
                    Res = true;
                    HubConnected = true;
                    HubConnectionNew.ServerTimeout = TimeSpan.FromSeconds(100000);
                    
                }                        
            }
            else
            {
                EventLog.WriteEntry("Support", "Test calling Hub Active operation", EventLogEntryType.Information);

                var Response = HubConnectionNew.InvokeAsync<bool>("Active").Result;
                if (!Response)
                {
                    HubConnectionNew = null;
                    EventLog.WriteEntry("Support", "Problem calling Hub Active operation", EventLogEntryType.Error);
                    HubConnected = false;
                }
                else
                {
                    EventLog.WriteEntry("Support", "Successfully called Hub Active operation", EventLogEntryType.Information);
                    Res = true;
                    HubConnected = true;
                }
            }
        }
    }
    return Res;
}

protected virtual async Task StockPusherHubConnection_Connect()
{
    Exception exception = null;
    Exception except = null;

    try
    {
        if (HubConnectionNew != null)
        {
            lock (PreparingHub)
            {
                EventLog.WriteEntry("Support", string.Format("Attempt to connect to Hub for {0}", Connection), EventLogEntryType.Information);

                var HubConnect = HubConnectionNew?.StartAsync();
                HubConnect?.Wait();
                HubConnect?.ContinueWith(
                    task =>
                    {
                        try
                        {
                            if (task != null && task.IsFaulted)
                            {
                                EventLog.WriteEntry("Support", "Problem connecting to Hub for", EventLogEntryType.Error);
                                EventLog.WriteEntry("Support", task.Exception.Message, EventLogEntryType.Error);

                                exception = task?.Exception;
                                except = exception?.InnerException;
                                while (except != null)
                                {
                                    except = except?.InnerException;
                                    if (except != null)
                                        EventLog.WriteEntry("Support", except.Message, EventLogEntryType.Error);
                                }
                            }
                        }
                        catch { }
                    }
                ).Wait();
            }
        }

    }
    catch (Exception ex)
    {
    }
}

问题根源分析及解决方案

1. SignalR版本不兼容

客户端同时混用旧版Microsoft.AspNet.SignalR.Client和ASP.NET Core SignalR的HubConnectionBuilder,导致服务端与客户端连接协议不匹配,服务端无法维持有效连接,频繁释放Hub实例。

  • 解决:统一使用ASP.NET Core SignalR客户端库,移除旧版相关代码。

2. 同步阻塞调用引发连接异常

客户端大量使用.Wait()和.Result阻塞异步操作,易造成线程死锁或连接状态异常,服务端因未及时收到客户端心跳判定连接失效,释放Hub实例。

  • 解决:将客户端代码改为全异步模式,用await替代同步阻塞调用。

3. CORS配置不一致

服务端配置了DefaultPolicy但启用时使用PolicyName,可能导致CORS验证失败,服务端主动断开连接释放Hub。

  • 解决:确保CORS策略名称一致,或直接使用app.UseCors()启用默认策略。

4. Hub生命周期管理错误

若服务端Hub存在手动调用Dispose的逻辑,会导致Hub被提前释放。

  • 解决:检查Hub类代码,移除手动Dispose逻辑,确保资源释放符合SignalR生命周期要求。

5. 长轮询传输的稳定性问题

仅启用长轮询传输,依赖客户端定期发起请求维持连接,若请求不及时,服务端会释放连接。

  • 解决:允许多种传输方式(如HttpTransportType.WebSockets | HttpTransportType.LongPolling),优先使用WebSocket;同时调整客户端ServerTimeout和服务端ClientTimeoutInterval、KeepAliveInterval参数,确保心跳机制正常运行。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 19:04:57