跨外部API调用时DbContext已释放问题排查
我的Web应用调用外部API#1,该API会调用另一外部API#2,三者相互独立。Web应用单独调用任意API均正常,但通过API#1调用API#2时出现错误:
Cannot access a disposed context instance. A common cause of this error is disposing a context instance that was resolved from dependency injection and then later trying to use the same context instance elsewhere in your application. This may occur if you are calling 'Dispose' on the context instance, or wrapping it in a using statement. If you are using dependency injection, you should let the dependency injection container take care of disposing context instances.
Object name: '[MyDbContext]'
所有调用均已使用await,但API#2完成时似乎导致API#1提前结束,不过API#2能正常返回结果。此前未遇此类跨API调用问题,现寻求帮助。以下为代码概要:
Web应用代码
HttpClient client = new HttpClient(); List<string> payload = new() { "One", "Two", "Three", "Four" }; var result = await client.PostAsJsonAsync("http://url.ap1.com/dostuff", payload); var SomeObject so = JsonConvert.DeserializeObject<SomeObject>(result);
API#1代码
[HttpPost("dostuff")] public async Task<SomeOtherObject>DoStuff([FromBody]List<string> thePayload) { // 尝试在本地数据库查找数据 var SomeOtherObject soo = await _context.DbStuff.FirstOrDefaultAsync(c => c.Id == thePayload.Id); // 本地数据库没有,调用外部服务获取 if (soo == null) { HttpClient client = new HttpClient(); List<string> payload = new(){ "One", "Two", "Three", "Four" }; // 问题出在这里,此调用完成时会提前结束原始API请求 var result = await client.PostAsJsonAsync("http://url.ap2.com/dootherstuff", thePayload) soo = JsonConvert.DeserializeObject<SomeOtherObject>(result); // 此处做对象转换,逻辑省略 _context.DbStuff.Add(soo) await _context.SaveChangesAsync(); } return soo; }
API#2为第三方外部API,可正常返回结果。
更新1
Minimal API实现无效:
app.MapPost("/url1.dostuff" ...
Controller实现有效:
[HttpPost("/api/dostuff")] public async Task<List<SomeObject>> DoStuff([FromBody] List<string> payload) { // ... }
更新2 原始Minimal API伪代码
public static void RegisterStuffEndpoints(this WebApplication app) { var stuffGroup = app.MapGroup("api/dostuff").WithTags("DoStuff"); // 用于获取数据的端点 stuffGroup.MapPost("/dostuff", ([FromBody] List<string> source, StuffService service) => await TypedResults.Ok(service.DoStuff(source))); }
问题核心是Minimal API与Controller的依赖注入生命周期管理逻辑不同,导致DbContext被提前释放。
问题原因
Minimal API默认会在异步委托的等待阶段(比如调用API#2的await)提前回收请求上下文,此时请求范围的DbContext会被DI容器释放;而后续service.DoStuff中执行SaveChangesAsync时,会尝试使用已释放的上下文,从而触发错误。
Controller模式下,ASP.NET Core会完整持有请求上下文直到Action方法完全执行完毕,因此不会出现这个问题。
修复方法
1. 显式等待异步流程(推荐)
修改Minimal API的端点定义,将委托改为完整的异步方法,确保ASP.NET Core跟踪整个异步生命周期:
public static void RegisterStuffEndpoints(this WebApplication app) { var stuffGroup = app.MapGroup("api/dostuff").WithTags("DoStuff"); stuffGroup.MapPost("/dostuff", async ([FromBody] List<string> source, StuffService service) => { var data = await service.DoStuff(source); return TypedResults.Ok(data); }); }
这种写法会让框架明确等待所有异步操作完成后再释放请求范围内的服务,避免DbContext提前被回收。
2. 额外注意事项
- 不要手动创建
HttpClient,改用DI注入IHttpClientFactory创建实例,避免Socket资源耗尽问题; - 检查
StuffService.DoStuff方法,确保所有异步操作都正确使用await,没有遗漏导致的异步流程异常。
内容的提问来源于stack exchange,提问作者djack109




