如何让SignalR控制台客户端自动重连?问题排查求助
问题原因与解决方案
核心原因:WithAutomaticReconnect() 的行为特性
你使用了 .WithAutomaticReconnect(),SignalR 默认会自动尝试重连4次,间隔分别为0秒、2秒、10秒、30秒。只有当所有自动重连尝试都失败后,才会触发 Closed 事件。因此网站刚下线时,客户端还处于重试阶段,不会触发 Closed,自然看不到"Connection Lost"日志。
另外,你初始的 try-catch 仅包裹了第一次启动连接的代码,后续连接断开后的错误不会被这个 catch 捕获,所以也不会输出"Failed to connect to Website"。
修正方案
1. 监控重连全过程(保留自动重连)
添加 Reconnecting 和 Reconnected 事件,实时监控重连状态:
public class MyBot { HubConnection connection; public async Task RunAsync() { try { connection = new HubConnectionBuilder() .WithUrl("https://localhost:7178/MyHub") .WithAutomaticReconnect() .Build(); // 开始重连时触发 connection.Reconnecting += (error) => { Console.WriteLine($"正在尝试重连,错误原因:{error?.Message}"); return Task.CompletedTask; }; // 重连成功时触发 connection.Reconnected += (connectionId) => { Console.WriteLine($"重连成功,新连接ID:{connectionId}"); return connection.InvokeAsync("JoinBots"); }; // 所有重连尝试失败后触发 connection.Closed += async (error) => { Console.WriteLine("所有重连尝试失败,连接已关闭"); await Task.Delay(new Random().Next(0, 5) * 1000); try { await connection.StartAsync(); await connection.InvokeAsync("JoinBots"); } catch (Exception ex) { Console.WriteLine($"手动重连失败:{ex.Message}"); } }; connection.On<string, string>("DoSomething", (arg1, arg2) => { //Do Something }); await connection.StartAsync(); await connection.InvokeAsync("JoinBots"); Console.WriteLine("初始连接成功"); } catch (Exception ex) { Console.WriteLine($"初始连接失败:{ex.Message}"); } } }
2. 自定义重连逻辑(关闭自动重连)
若想完全自主控制重连流程,可去掉 .WithAutomaticReconnect(),直接在 Closed 事件中处理:
public class MyBot { HubConnection connection; public async Task RunAsync() { try { connection = new HubConnectionBuilder() .WithUrl("https://localhost:7178/MyHub") // 去掉自动重连,自定义逻辑 .Build(); connection.Closed += async (error) => { Console.WriteLine($"连接断开,错误原因:{error?.Message}"); // 无限重试直到连接成功 while (true) { try { await Task.Delay(new Random().Next(0, 5) * 1000); await connection.StartAsync(); await connection.InvokeAsync("JoinBots"); Console.WriteLine("重连成功"); break; } catch (Exception ex) { Console.WriteLine($"重连失败,将重试:{ex.Message}"); } } }; connection.On<string, string>("DoSomething", (arg1, arg2) => { //Do Something }); await connection.StartAsync(); await connection.InvokeAsync("JoinBots"); Console.WriteLine("初始连接成功"); } catch (Exception ex) { Console.WriteLine($"初始连接失败:{ex.Message}"); } } }
关键注意点
- 异步事件处理程序(如
Closed)内部必须添加try-catch,否则异常会被静默吞掉,无法查看错误信息。 - 若使用自动重连,可通过
.WithAutomaticReconnect(new int[] { 0, 2000, 10000, 30000 })自定义重试间隔,或实现IRetryPolicy接口完全自定义重试逻辑。
内容的提问来源于stack exchange,提问作者Bagzli
相关产品推荐
相关产品推荐

