SignalR客户端未执行connection.on方法问题求助
解决SignalR服务端发消息客户端收不到的问题
从你的代码来看,有几个关键问题导致客户端无法接收消息,我逐个给你分析并提供修复方案:
1. BackgroundService未保持长期运行,连接被释放
你的Worker类继承自BackgroundService,但ExecuteAsync方法执行到注册回调后就直接结束了。BackgroundService的设计逻辑是:当ExecuteAsync方法完成时,服务会停止,这时候你的SignalR连接会被自动释放,后续服务端发消息时客户端已经处于断开状态,自然收不到消息。
修复方案:在ExecuteAsync中添加长期运行的循环逻辑,监听停止令牌,保持服务持续运行:
protected override async Task ExecuteAsync(CancellationToken stoppingToken) { using (StreamWriter writer = new StreamWriter(@"C:\Users\devma\source\repos\WorkerService1\WorkerService1\TextFile1.txt")) { writer.WriteLine("bigin"); } var ip = GetLocalIPAddress(); ip = "localhost"; connection = new HubConnectionBuilder() .WithUrl("https://localhost:44339/dschub" , options => { options.WebSocketConfiguration = conf => { conf.RemoteCertificateValidationCallback = (message, cert, chain, errors) => true; }; options.HttpMessageHandlerFactory = factory => new HttpClientHandler { ServerCertificateCustomValidationCallback = (message, cert, chain, errors) => true }; } ) .Build(); // 先注册所有回调,再启动连接(关键!避免漏接消息) connection.On<string>("calldscclient", (message) => { using (StreamWriter writer = new StreamWriter(@"C:\Users\devma\source\repos\WorkerService1\WorkerService1\TextFile1.txt")) { writer.WriteLine($"Received message: {message}"); writer.WriteLine("Monica Rathbun"); } }); // 添加自动重连逻辑,应对网络波动 connection.Closed += async (error) => { _logger.LogWarning("SignalR connection closed, attempting reconnect..."); await Task.Delay(new Random().Next(0, 5) * 1000); try { await connection.StartAsync(stoppingToken); await connection.InvokeAsync("dscRegister", ip, stoppingToken); } catch (Exception ex) { _logger.LogError(ex, "Reconnect failed"); } }; // 启动连接并注册客户端 try { await connection.StartAsync(stoppingToken); await connection.InvokeAsync("dscRegister", ip, stoppingToken); _logger.LogInformation("SignalR connection established"); } catch (Exception ex) { _logger.LogError(ex, "Failed to start SignalR connection"); } // 保持服务运行,直到收到停止信号 await Task.Delay(Timeout.Infinite, stoppingToken); }
2. 回调注册时机太晚
你之前是在StartAsync和InvokeAsync("dscRegister")之后才注册calldscclient回调,如果dscRegister的服务端方法触发了消息发送,或者服务端在客户端注册回调前就发了消息,客户端是收不到的。一定要在启动连接前注册所有回调,确保客户端能接收所有后续消息。
3. 服务端可能错误注入Hub实例
在ASP.NET Core SignalR中,不能直接注入Hub类的实例(比如你的_hub),因为Hub是为每个连接创建的临时对象,直接注入的实例无法正确对应到客户端连接。正确的做法是注入IHubContext<YourHub>来发送消息。
服务端修复示例:
假设你的Hub类叫DscHub,先通过构造函数注入IHubContext<DscHub>:
private readonly IHubContext<DscHub> _hubContext; private readonly IDscService _dscService; // 构造函数注入IHubContext public YourController(IHubContext<DscHub> hubContext, IDscService dscService) { _hubContext = hubContext; _dscService = dscService; } [HttpGet("servedsc")] public async Task<ActionResult> ServeDsc() { var remoteIpAddress = HttpContext.Request.Host.Host; var desUserList = await _dscService.GetDscUser(remoteIpAddress); var targetConnectionId = desUserList.FirstOrDefault()?.DscConnectionId; if (!string.IsNullOrEmpty(targetConnectionId)) { // 给指定连接发消息(比发给所有人更精准,避免无效推送) await _hubContext.Clients.Client(targetConnectionId).SendAsync("calldscclient", targetConnectionId); } return Ok(desUserList); }
4. 额外建议:添加日志排查问题
在客户端的连接事件中添加日志,方便快速定位连接状态问题:
// 连接重连成功日志 connection.Reconnected += (connectionId) => { _logger.LogInformation("SignalR reconnected with id: {ConnectionId}", connectionId); return Task.CompletedTask; }; // 正在重连日志 connection.Reconnecting += (error) => { _logger.LogWarning("SignalR reconnecting due to error: {Error}", error?.Message); return Task.CompletedTask; };
按照上面的步骤修改后,应该就能解决客户端收不到消息的问题了。
内容的提问来源于stack exchange,提问作者Manoj
相关产品推荐
相关产品推荐

