You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Entity Framework:已释放上下文实例访问异常排查求助

问题分析与解决方案

核心原因

你遇到的System.ObjectDisposedException本质是Scoped生命周期的DbContext被提前释放,而后续代码仍在尝试使用它。最常见的触发场景是:异步方法调用时未正确使用await,导致请求上下文提前结束,DI容器自动释放了Scoped的DbContext实例。

排查与修复步骤

1. 强制所有异步调用使用await

这是最可能的根因:

  • 检查控制器中调用ProcessReceipt的代码,必须添加await:
    // 错误写法:无await,请求结束后DbContext会被释放
    // _accountsHelpers.ProcessReceipt(receipt);
    
    // 正确写法
    await _accountsHelpers.ProcessReceipt(receipt);
    
  • 检查ProcessReceipt内部调用MarkTransactionAsPaid的代码,同样必须用await:
    public async Task ProcessReceipt(Receipt receipt)
    {
        // ...其他逻辑
        // 必须await,确保DbContext在操作完成前不会被释放
        await MarkTransactionAsPaid(paymentId, receipt.yourPaymentReference, receipt.receiptId);
        // ...
    }
    

2. 确认服务生命周期匹配

  • 确保RGDbContext是Scoped注册(默认AddDbContext的生命周期就是Scoped),与AccountsHelpers的Scoped生命周期保持一致:
    // Program.cs中DbContext的注册(默认即可)
    builder.Services.AddDbContext<RGDbContext>(options => 
        options.UseSqlServer(builder.Configuration.GetConnectionString("YourConnString")));
    
    这样每个请求中,AccountsHelpers和RGDbContext会被同时创建、同时释放,不会出现生命周期不匹配的问题。

3. 排查手动Dispose操作

检查MarkTransactionAsPaid或ProcessReceipt中是否存在手动调用_context.Dispose()的代码,或者用using包裹DbContext的逻辑(构造注入的DbContext不应手动释放)。

4. 备选方案:使用IDbContextFactory(若上述方法无效)

如果异步操作存在跨请求延迟执行的场景(比如后台任务),可以改用IDbContextFactory创建独立的DbContext实例,避免依赖Scoped生命周期:

  • 注册DbContextFactory:
    builder.Services.AddDbContextFactory<RGDbContext>(options =>
        options.UseSqlServer(builder.Configuration.GetConnectionString("YourConnString")));
    
  • 修改AccountsHelpers的构造注入与方法实现:
    public class AccountsHelpers
    {
        private readonly IDbContextFactory<RGDbContext> _contextFactory;
        // 其他依赖...
    
        public AccountsHelpers(IDbContextFactory<RGDbContext> contextFactory, IMapper mapper, IConfiguration settings, IAzureHelpers azureHelpers)
        {
            _contextFactory = contextFactory;
            _mapper = mapper;
            _settings = settings;
            _azureHelpers = azureHelpers;
        }
    
        public async Task<InfoBool> MarkTransactionAsPaid(int paymentId, string pspReference, string receiptId)
        {
            using var context = _contextFactory.CreateDbContext();
            try
            {
                MoneyTransaction? foundtransaction =
                    await context.MoneyTransactions
                        .Where(p => p.Id == paymentId)
                        .Include(p => p.User)
                        .FirstOrDefaultAsync();
    
                // ...业务逻辑
    
                await context.SaveChangesAsync();
                return new InfoBool { Success = true };
            }
            catch (Exception ex)
            {
                return new InfoBool { Success = false, Message = ex.Message };
            }
        }
    }
    
    这种方式会在每次方法调用时创建独立的DbContext实例,彻底避免生命周期冲突问题。

内容的提问来源于stack exchange,提问作者Brett JB

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 00:43:20