SignalR Hub已释放引发ObjectDisposedException问题求助
解决SignalR中"Cannot access a disposed object. Object name: 'SHHub'"错误
问题原因
这个错误是因为当前的SHHub实例已被SignalR框架释放,但你仍尝试访问它的Clients属性。通常出现在以下场景:
- Hub方法中存在未正确
await的异步操作,导致线程阻塞,SignalR提前回收Hub实例 - 方法内的耗时操作(如数据库读写)超出SignalR的Hub实例生命周期,导致实例被释放
- 直接依赖当前Hub实例的
Clients属性发消息,而非全局的IHubContext
解决方案
1. 确保所有异步操作正确使用await
检查DBService.GetMultiPlayerById和DBService.SaveMultiPlayer方法,确保它们是原生异步实现,且调用时都添加了await。如果是同步代码包装的异步(比如用Task.Run),可能引发线程上下文问题,建议调整为原生异步数据库操作。
2. 使用IHubContext替代当前Hub实例发送消息
IHubContext是SignalR提供的全局上下文对象,不依赖单个Hub实例的生命周期,是跨场景发送消息的标准方式。
修改步骤:
- 在
SHHub的构造函数中注入IHubContext<SHHub>:
private readonly IHubContext<SHHub> _hubContext; public SHHub(IHubContext<SHHub> hubContext) { _hubContext = hubContext; }
- 将Start方法中最后一行发消息的代码替换为:
await _hubContext.Clients.Group(pMultiPlayerId).SendAsync("StartedGame", $"{oNickName} has started the game");
3. 优化耗时操作
如果数据库操作确实耗时较长,建议将这类操作移到后台服务(比如IHostedService),操作完成后再通过IHubContext发送消息,避免长时间占用Hub实例导致被回收。
为什么Join方法能正常工作?
Join方法内的操作逻辑简单、执行速度快,在Hub实例被释放前就完成了消息发送。而Start方法需要遍历所有玩家并更新状态,加上数据库保存操作,耗时稍长,刚好触发了SignalR的实例回收机制。
内容的提问来源于stack exchange,提问作者user2103317
相关产品推荐
相关产品推荐

