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

SignalR 2事件处理方法运行一段时间后不再触发的问题

SignalR 2 客户端事件处理方法一段时间后停止触发的问题

我基于SignalR 2实现的应用启动初期运行正常,但运行一段时间(5到30分钟不等)后,NewMessage事件处理方法不再被调用。经确认,服务器与客户端仍保持连接:客户端SignalR日志显示仍能接收服务器指令,客户端发送的消息也能被服务器接收并执行,连接状态检查结果也正常。

以下是我的实现代码:

public void ConnectAsync()
{
    WriteToLogs("Connecting to Server...");
    var dic = new Dictionary<string, string> { { "UserName", _signalrSettings.ApplicationName } };
    _hubConnection?.Dispose();
    _hubConnection = new HubConnection(_signalrSettings.ServerUri, dic);
    _hubConnection.StateChanged += Connection_StateChanged;
    _hubProxy = _hubConnection.CreateHubProxy(_signalrSettings.HubProxy);
    try
    {
        _hubProxy.On<string, string>("Initial", (a, b) => Initial());
       
        _hubConnection.Start().ContinueWith((s) =>
        {
            if (s.IsCompleted)
            {
                _isCompleted = true;
            }
            else if (s.IsCanceled)
            {
                _isCompleted = false;
            }
            else if (s.IsFaulted)
            {
                _isCompleted = false;
            }
            _hubProxy.On<string, string>("NewMessage", (userName, message) => NewMessage(userName, message)); // 一段时间后该事件不再触发
            WriteToLogs( $@"Connection status is {_hubConnection.State}");
        }).Wait();
    }
    catch (Exception e)
    {
        var trace = new StackTrace(e, true);

        var reflectedType = trace.GetFrame(0).GetMethod().ReflectedType;
        if (reflectedType != null)
        {
            _messageOperation.WriteErrors($@"Error {e.StackTrace} at {trace}");
        }
    }
}

问题原因

核心问题在于事件注册的时机错误:你把NewMessage事件的注册放在了Start()的ContinueWith回调里。SignalR连接如果发生自动重连(即使你没手动写重连逻辑,底层也可能因网络波动触发重连),重连会重建连接上下文,而ContinueWith回调只在第一次启动成功时执行一次,重连后不会再触发这个回调,导致NewMessage事件没有被重新注册,自然不会再触发。

另外,ContinueWith的回调在后台线程执行,虽然SignalR客户端API大多线程安全,但事件注册逻辑放在这里也存在潜在的线程安全风险。

解决方案

1. 统一事件注册时机(核心修复)

把所有事件注册(包括Initial和NewMessage)移到_hubConnection.Start()之前,这样每次创建连接时都会重新绑定事件处理方法,即使后续重连,只要重新初始化连接,事件就会被重新注册。

修改后的代码:

public void ConnectAsync()
{
    WriteToLogs("Connecting to Server...");
    var dic = new Dictionary<string, string> { { "UserName", _signalrSettings.ApplicationName } };
    _hubConnection?.Dispose();
    _hubConnection = new HubConnection(_signalrSettings.ServerUri, dic);
    _hubConnection.StateChanged += Connection_StateChanged;
    _hubProxy = _hubConnection.CreateHubProxy(_signalrSettings.HubProxy);
    try
    {
        // 所有事件注册移到连接启动前,确保每次初始化连接都绑定
        _hubProxy.On<string, string>("Initial", (a, b) => Initial());
        _hubProxy.On<string, string>("NewMessage", (userName, message) => NewMessage(userName, message));
       
        _hubConnection.Start().ContinueWith((s) =>
        {
            if (s.IsCompleted)
            {
                _isCompleted = true;
            }
            else if (s.IsCanceled)
            {
                _isCompleted = false;
            }
            else if (s.IsFaulted)
            {
                _isCompleted = false;
            }
            WriteToLogs( $@"Connection status is {_hubConnection.State}");
        }).Wait();
    }
    catch (Exception e)
    {
        var trace = new StackTrace(e, true);

        var reflectedType = trace.GetFrame(0).GetMethod().ReflectedType;
        if (reflectedType != null)
        {
            _messageOperation.WriteErrors($@"Error {e.StackTrace} at {trace}");
        }
    }
}

2. 补充重连逻辑(可选)

如果你的客户端需要处理网络波动导致的断开,可以监听StateChanged事件,当连接从Disconnected切换到Connecting时,重新调用ConnectAsync方法,确保每次重连都能重新初始化连接并注册事件。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 20:25:58