.NET Razor应用多线程报错:无法访问已释放对象(DbContext已释放)
问题解决方案
核心原因
注入的AppDbContext默认是Scoped生命周期,会在当前请求结束后被DI容器自动释放。你在OnPostSignup方法结束后(请求上下文销毁),后台线程仍尝试使用已释放的上下文,因此触发Cannot access a disposed object错误。
解决步骤
1. 注入DbContext工厂
在页面模型的构造函数中注入IDbContextFactory<AppDbContext>,用于在后台线程中创建独立的上下文实例:
private readonly AppDbContext _context; private readonly IDbContextFactory<AppDbContext> _contextFactory; public YourPageModel(AppDbContext context, IDbContextFactory<AppDbContext> contextFactory) { _context = context; _contextFactory = contextFactory; }
2. 修改后台任务调用逻辑
不再传递原上下文,改用Task.Run执行异步后台任务(避免使用Thread,因为它无法正确处理异步方法的等待逻辑):
public async Task<JsonResult> OnPostSignup(MarketOperator MarketOperator, Boolean Confirm = false) { // 执行当前请求内的数据库操作 _context.Attach(RAExists).State = EntityState.Modified; await _context.SaveChangesAsync(); // 启动后台异步任务,不阻塞当前请求 _ = Task.Run(async () => await AI_Creation(_contextFactory, MarketOperator.MarketDescription, MarketOperator.MOID)); return new JsonResult(new { success = true }); }
3. 重构AI_Creation方法
在方法内通过工厂创建新的上下文,并使用using语句管理其生命周期:
public async Task<IActionResult> AI_Creation(IDbContextFactory<AppDbContext> contextFactory, string idea, int moid) { try { // 调用OpenAI接口的业务代码(保持不变) // ... // 创建独立的DbContext实例 using var dbContext = contextFactory.CreateDbContext(); MarketOperator mo = await dbContext.MarketOperator.FirstOrDefaultAsync(ra => ra.MOID == moid); if (mo == null) { return NotFound(); } mo.Keywords = aI_Answers.keywords; // 从数据库查询的实体已被上下文跟踪,无需手动Attach await dbContext.SaveChangesAsync(); return Ok(); } catch (Exception ex) { // 捕获并处理后台任务中的异常,避免进程崩溃 // 可添加日志记录逻辑 return StatusCode(500); } }
额外注意事项
- 若后台任务执行时间较长(如超过数分钟),建议使用Hangfire、Quartz等专业后台任务框架,避免应用池回收导致任务中断。
- 务必处理后台任务中的异常,未捕获的异常可能导致应用进程意外终止。
内容的提问来源于stack exchange,提问作者kaielx
相关产品推荐
相关产品推荐

