Web API Core启动时用EF Core更新数据库报对象已释放错误如何解决
问题根因
PopulateSomeTable方法使用了async void签名,异步逻辑没有被等待就直接返回,Configure方法执行完毕后,从依赖注入容器解析到的SomeDBContext属于Scoped生命周期,会随方法执行结束被自动销毁,后续异步逻辑里再访问上下文就会触发已释放错误。- ASP.NET Core启动阶段直接在
Configure方法参数中注入Scoped类型服务本身不符合生命周期规范,Scoped服务默认的作用域绑定请求链路,启动阶段没有请求上下文,直接注入的实例生命周期不受控。
修复方案
方案1:调整为同步初始化(快速修复)
将异步读写逻辑改成同步,保证所有数据库操作在Configure方法执行完毕前完成,避免上下文提前释放。
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, SomeDBContext dataContext, ILoggerFactory loggerFactory) { // 原有其他逻辑 // 自动执行数据库迁移 dataContext.Database.Migrate(); PopulateSomeTable(dataContext); } private void PopulateSomeTable(SomeDBContext context) { var someTables = context.SomeTables; if (someTables != null && someTables.Count() == 0) { someTables.Add(new Entities.SomeTable { someProperty1= 20, someProperty2 = "Something", someProperty3 = DateTimeOffset.Now, }); context.SaveChanges(); } }
方案2:手动创建作用域执行异步初始化(规范推荐)
如果需要保留异步逻辑,手动创建Scoped作用域获取上下文,等待异步逻辑执行完成后再销毁作用域,完全符合依赖注入生命周期规则。
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory) { // 原有其他逻辑 // 手动创建作用域处理数据库操作 using (var scope = app.ApplicationServices.CreateScope()) { var dataContext = scope.ServiceProvider.GetRequiredService<SomeDBContext>(); // 执行迁移 dataContext.Database.Migrate(); // 等待异步初始化完成再释放作用域 PopulateSomeTableAsync(dataContext).Wait(); } } // 异步方法签名改为返回Task,禁止用async void private async Task PopulateSomeTableAsync(SomeDBContext context) { var someTables = context.SomeTables; if (someTables != null && (await someTables.CountAsync()) == 0) { someTables.Add(new Entities.SomeTable { someProperty1= 20, someProperty2 = "Something", someProperty3 = DateTimeOffset.Now, }); await context.SaveChangesAsync(); } }
注意事项
- 除了系统事件回调场景外,禁止使用
async void定义异步方法,统一使用Task/Task<T>作为返回值,方便调用方控制异步执行流程。 - 启动阶段需要访问Scoped生命周期服务时,不要直接在
Configure参数中注入,必须通过根服务提供者手动创建作用域后解析获取。
内容的提问来源于stack exchange,提问作者James
相关产品推荐
相关产品推荐

