使用await触发ObjectDisposedException的C#异步代码问题及解决
问题:异步调用DbContext触发ObjectDisposedException,使用.Result却正常?
我有一个异步函数,调用DbContext时遇到问题:用await调用会触发ObjectDisposedException,但用.Result能得到正确结果。不过听说.Result会阻塞线程,不建议使用。
异常代码示例:
public async void AggrigateData() { // some code var machineEvents = await _eventService.GetAllErrorEventsAsync(); // 无法正常运行 var machineEvents = _eventService.GetAllErrorEventsAsync().Result; // 可正常运行 var differentEventIds = machineEvents.Labels.Count; // 获取结果后立即使用 // some code }
请问该如何解决?这里用.Result是否有问题?我获取结果后会立即统计Labels数量。
补充背景
AggregateData由事件处理器调用,定时器不支持async Task,没法直接改成异步任务;之前尝试把DoWork改成async void,以为问题只是后移,没解决根本问题:
public Task StartAsync(CancellationToken stoppingToken) { _timer = new Timer(DoWork, null, TimeSpan.Zero, TimeSpan.FromHours(1)); return Task.CompletedTask; } private void DoWork(object state) { machineEvaluationService.AggrigateData(); }
已解决的方案
修改代码后问题解决,调整后的代码如下:
// IHostedService的StartAsync,定时器部分保持不变 public Task StartAsync(CancellationToken stoppingToken) { _timer = new Timer(DoWork, null, TimeSpan.Zero, TimeSpan.FromHours(1)); return Task.CompletedTask; } // 将DoWork改为async void,内部await异步方法 private async void DoWork(object state) { await machineEvaluationService.AggregateData(); } // 改为async Task的AggregateData public async Task AggrigateData() { // some code var machineEvents = await _eventService.GetAllErrorEventsAsync(); var differentEventIds = machineEvents.Labels.Count; // some code }
原因解释
原代码问题根源:
原AggregateData是async void方法,当同步的DoWork调用它时,方法执行到await就会立即返回,DoWork执行完毕后,当前作用域的DbContext可能被提前释放。后续await的GetAllErrorEventsAsync尝试访问已释放的上下文,就会抛出ObjectDisposedException。而.Result是阻塞调用,强制等待异步操作完成,DbContext在整个过程中保持存活,所以不会报错,但阻塞线程确实会带来性能和死锁风险。修改后生效的原因:
- 将
DoWork改为async void(定时器回调场景是少数允许使用async void的场景),内部await AggregateData,确保AggregateData的异步操作被完整等待,不会提前返回。 AggregateData改为async Task,让异步流程的状态被正确跟踪,DbContext的生命周期可以覆盖到所有异步操作完成,避免被提前释放。
- 将
内容的提问来源于stack exchange,提问作者Rafael Eberle
相关产品推荐
相关产品推荐

