ASP.NET Core+Autofac中二次Mediator调用触发ObjectDisposedException求助
问题描述
在一个方法内执行两次Mediator调用时,第二次调用总是触发ObjectDisposedException,错误信息如下:
System.ObjectDisposedException: Instances cannot be resolved and nested lifetimes cannot be created from this LifetimeScope as it (or one of its parent scopes) has already been disposed
简化代码
MainLogic.cs(注册为Transient)
private readonly IDateTimeProvider _dateTimeProvider; // 注册为Singleton private readonly IMediator _mediator; // Autofac默认注册为Transient public MainLogic(IDateTimeProvider dateTimeProvider, IMediator mediator) { _dateTimeProvider = dateTimeProvider; _mediator = mediator; } public async Task<List<myObj>> MainProcessingLogic(string key, List<SomeObj> listOfItems, DateTime dateTime) { try { var myVar = (await _mediator.Send(new ProcessSomeQuery(key, listOfItems, dateTime))).FirstOrDefault(); } catch (Exception ex) { _logger.LogError("ProcessSomeQuery ran into an error : " + ex); } try { var myVar = await _mediator.Send(new ProcessSomeOtherDifferentQuery(key, listOfItems, dateTime)); } catch (Exception ex) { _logger.LogError("ProcessSomeOtherDifferentQuery ran into an error : " + ex); } // ...其他代码 }
ProcessSomeQueryHandler(依赖IMyDataBaseContext,Autofac默认注册为Transient)
private readonly IMyDataBaseContext _myDatabaseContext; private readonly ILogger<ProcessSomeQueryHandler> _logger; public ProcessSomeQueryHandler(IMyDataBaseContext myDatabaseContext, ILogger<ProcessSomeQueryHandler> logger) { _myDatabaseContext = myDatabaseContext; _logger = logger; }
ProcessSomeOtherDifferentQueryHandler(仅依赖Logger)
private readonly ILogger<ProcessSomeOtherDifferentQueryHandler> _logger; public ProcessSomeOtherDifferentQueryHandler(ILogger<ProcessSomeOtherDifferentQueryHandler> logger) { _logger = logger; }
异常现象
- 仅第二次Mediator调用报错;调换调用顺序后,原第一个调用会在第二次执行时报错
- 两次调用同一
ProcessSomeQuery,第二次仍会报错 - 无论第二个查询是否注入数据库上下文,第二次调用均报错
- 调整各类作用域配置无效
- 移除
ProcessSomeQuery的数据库上下文注入后,无报错
服务注册配置
services.AddTransient<IMainLogic, MainLogic>(); services.AddSingleton<IDateTimeProvider, DateTimeProvider>(); // IMediator由Autofac注册,默认Transient // MyDataBaseContext由Autofac注册,默认Transient
解决方案
1. 移除手动释放数据库上下文的代码
检查ProcessSomeQueryHandler的实现,若存在手动调用_myDatabaseContext.Dispose()的逻辑,必须删除。Autofac会自动管理依赖实例的生命周期,手动释放会导致该实例绑定的作用域被标记为已释放,后续所有依赖该作用域的操作都会抛出异常。
2. 调整Mediator和数据库上下文的生命周期为Scoped
将IMediator和IMyDataBaseContext注册为InstancePerLifetimeScope(即Scoped),确保同一作用域内的实例复用且作用域存活期间实例有效:
// Autofac注册代码 builder.RegisterType<Mediator>().As<IMediator>().InstancePerLifetimeScope(); builder.RegisterType<MyDataBaseContext>().As<IMyDataBaseContext>().InstancePerLifetimeScope();
3. 在独立作用域内执行两次Mediator调用
如果当前上下文没有现成的活跃作用域,可手动创建一个作用域,确保两次调用都在同一作用域内执行:
修改MainLogic注入ILifetimeScope
private readonly IDateTimeProvider _dateTimeProvider; private readonly ILifetimeScope _lifetimeScope; public MainLogic(IDateTimeProvider dateTimeProvider, ILifetimeScope lifetimeScope) { _dateTimeProvider = dateTimeProvider; _lifetimeScope = lifetimeScope; }
在方法内使用作用域执行调用
public async Task<List<myObj>> MainProcessingLogic(string key, List<SomeObj> listOfItems, DateTime dateTime) { using (var scope = _lifetimeScope.BeginLifetimeScope()) { var scopedMediator = scope.Resolve<IMediator>(); try { var myVar = (await scopedMediator.Send(new ProcessSomeQuery(key, listOfItems, dateTime))).FirstOrDefault(); } catch (Exception ex) { _logger.LogError("ProcessSomeQuery ran into an error : " + ex); } try { var myVar2 = await scopedMediator.Send(new ProcessSomeOtherDifferentQuery(key, listOfItems, dateTime)); } catch (Exception ex) { _logger.LogError("ProcessSomeOtherDifferentQuery ran into an error : " + ex); } } // ...其他代码 }
内容的提问来源于stack exchange,提问作者SushiCode
相关产品推荐
相关产品推荐

