Grpc请求后DbContext被释放,执行UpdateManyQuantity时抛异常
解决ASP.NET中异步Grpc调用后DbContext被释放的问题
问题根源
Scoped生命周期的DbContext默认和请求Scope绑定,处理OrderConfirmEvent或PaymentRejectedEvent时,异步Grpc调用会让当前线程释放原有Scope,等Grpc响应返回后,原DbContext已被DI容器回收,后续执行UpdateManyQuantity自然会抛出ObjectDisposedException。而同步的OrderCreatedEvent全程在同一个Scope内执行,所以不会出现这个问题。
可行解决方案
1. 手动创建新Scope包裹DbContext操作
通过注入IServiceScopeFactory,在Grpc调用完成后,手动创建新Scope,在这个Scope内获取DbContext执行数据库操作,确保操作时DbContext处于有效状态。示例代码:
private readonly IServiceScopeFactory _scopeFactory; private readonly IOrderGrpcService _orderGrpcService; // 构造函数注入依赖 public OrderEventHandler(IServiceScopeFactory scopeFactory, IOrderGrpcService orderGrpcService) { _scopeFactory = scopeFactory; _orderGrpcService = orderGrpcService; } public async Task Handle(OrderConfirmEvent @event) { // 异步调用Grpc获取订单商品 var orderItems = await _orderGrpcService.GetOrderItems(@event.OrderId); // 创建新Scope并获取DbContext using var scope = _scopeFactory.CreateScope(); var dbContext = scope.ServiceProvider.GetRequiredService<YourDbContext>(); // 执行库存更新并保存 await dbContext.UpdateManyQuantity(orderItems); await dbContext.SaveChangesAsync(); }
2. 调整事件处理的Scope生命周期
如果使用MediatR这类事件框架,可以将事件处理器的生命周期配置为Scoped,或者确保整个事件处理流程在同一个Scope内完成。核心是让DbContext的生命周期覆盖从Grpc调用到数据库操作的全流程,避免中途被回收。
注意事项
- 不要在异步操作外部持有Scoped服务的引用,尤其是
DbContext,一旦Scope被释放,引用就会失效。 - 手动创建Scope时必须用
using语句,确保Scope用完后被正确释放,防止资源泄漏。
内容的提问来源于stack exchange,提问作者Xaby
相关产品推荐
相关产品推荐

