添加DI后SignalR的MainHub连接建立后崩溃问题排查
为SignalR的MainHub添加依赖注入(注入ReadingsModel)后,WebSocket连接建立后随即崩溃;未添加DI的MainHub则可正常运行。相关代码如下:
前端JS代码
const localConnection = new signalR.HubConnectionBuilder() .withUrl("/mainhub") .configureLogging(signalR.LogLevel.Debug) .withAutomaticReconnect([0, 10, 30, 60, 90, 150]) .build(); async function start() { try { await connection.start(); console.log("SIGNALR connected with NANO SERWER"); await localConnection.start(); console.log("LOCAL signalR connection established.") } catch (err) { console.log(err); setTimeout(start, 35000); } }; connection.onclose(async () => { await start(); }); // Start the connection. start();
未崩溃的MainHub代码
public class MainHub : Hub<IMainHub> { public async Task ConnectionState(string isConnected) { await Clients.All.ConnectionState(isConnected); } }
添加DI后崩溃的MainHub代码
public class MainHub : Hub<IMainHub> { private readonly ReadingsModel _readings; public MainHub(ReadingsModel readings) { _readings= readings; } public async Task ConnectionState(string isConnected) { await Clients.All.ConnectionState(isConnected); } }
ReadingsModel未在DI容器中注册:SignalR的Hub实例由依赖注入容器负责创建,如果
ReadingsModel没有被注册到容器中,容器无法解析该类型,会导致Hub初始化失败,直接引发连接崩溃。解决方法是在项目的服务配置代码(如Program.cs或Startup.cs)中添加注册逻辑,例如:// 根据实际需求选择生命周期:Scoped/Singleton/Transient builder.Services.AddScoped<ReadingsModel>();ReadingsModel的生命周期与Hub不兼容:SignalR Hub默认的生命周期是Scoped(每个连接对应一个Hub实例)。如果
ReadingsModel被注册为Singleton,但它内部依赖了Scoped生命周期的服务,就会出现生命周期冲突,导致实例创建失败。需要根据ReadingsModel的实际使用场景调整生命周期:- 若
ReadingsModel无状态且可共享,可保持Singleton注册; - 若
ReadingsModel需要每个连接独立实例,改为Scoped注册; - 若每次使用都需要新实例,使用Transient注册。
- 若
ReadingsModel的构造函数存在异常:如果
ReadingsModel的构造函数本身存在未处理的异常(比如它依赖的其他服务未注册、构造逻辑出错),那么在创建ReadingsModel实例时会抛出异常,导致Hub无法初始化,连接随即崩溃。需要检查ReadingsModel的构造代码,确保其能正常创建实例,所有依赖都已正确注册。
另外,前端代码存在一个小问题:start函数中调用的connection变量未定义,应该改为localConnection,否则前端也会报错,但这不是导致WebSocket连接崩溃的直接原因。
内容的提问来源于stack exchange,提问作者Software Architect

