ASP.NET Core 5 SignalR Hub(ABP vNext)依赖注入及连接已释放问题如何解决
问题根本原因
- SignalR连接断开触发
OnDisconnectedAsync时,客户端的请求生命周期已经结束,ABP框架默认绑定到请求上下文的工作单元(UOW)、DbContext连接均已被释放,你直接注入的仓储依赖的是已经销毁的DbContext实例,所以会抛出连接取消/释放的异常。 - 哪怕Hub和仓储本身是瞬态生命周期,仓储依赖的DbContext属于已结束的请求作用域,已经被回收,所以无法正常执行数据库操作。
解决方法
手动创建独立的工作单元来包裹数据库操作,因为你继承了AbpHub可以直接使用内置的UnitOfWorkManager属性无需额外注入,修改后的代码如下:
[Authorize(Roles = RoleResources.Collector)] public class CollectorHub : AbpHub { private readonly CollectorManager _manager; private readonly IRepository<Collector, Guid> _repository; private readonly ICacheManager<string, CollectorSession> _sessionCache; public CollectorHub( CollectorManager manager, IRepository<Collector, Guid> repository, ICacheManager<string, CollectorSession> sessionCache) { _manager = manager; _repository = repository; _sessionCache = sessionCache; } public override async Task OnDisconnectedAsync(Exception e) { var collectorId = GetCollectorId(); var connectionId = Context.ConnectionId; _sessionCache.Remove(connectionId); // 手动开启全新的独立工作单元,不依赖已销毁的请求上下文 using (var uow = UnitOfWorkManager.Begin(requiresNew: true)) { // 传入CancellationToken.None避免使用已触发取消的上下文令牌 var collector = await _repository.FindAsync(collectorId, cancellationToken: CancellationToken.None); if (collector != null) { collector.CommunicationState = CommunicationState.Offline; await _repository.UpdateAsync(collector, autoSave: true, cancellationToken: CancellationToken.None); } // 手动提交工作单元改动 await uow.CompleteAsync(); } await base.OnDisconnectedAsync(e); } }
核心注意事项
- 调用
UnitOfWorkManager.Begin必须传入requiresNew: true,强制创建完全独立的工作单元,不会复用已销毁的请求上下文资源 - 所有数据库操作传入
CancellationToken.None,避免触发OnDisconnectedAsync自带的已经处于取消状态的令牌 - 必须手动调用
await uow.CompleteAsync(),否则工作单元不会提交改动到数据库
内容的提问来源于stack exchange,提问作者XuRui
相关产品推荐
相关产品推荐

