实体框架 无法访问已释放的上下文实例 - 但工作方式是从外部控制器调用的

Entity Framework Cannot access a disposed context instance - but works called from external controller

提问人:Brett JB 提问时间:11/16/2023 最后编辑:Brett JB 更新时间:11/17/2023 访问量:59

问:

在控制器中处理交易时,我在“accountsHelpers”库中有一个函数,用于将付款标记为已付款。控制器越来越重,所以我在“accountsHelpers”中创建了一个“processReceipt”函数来保持控制器的轻量级。这是学术性的,但提供了一个背景。

在帮助程序中创建“processReceipt”函数后,我看到它不再起作用,因为当它在同一帮助程序库中调用“MarkTransactionAsPaid”函数时,我收到此错误:

System.ObjectDisposedException HResult=0x80131622 Message=无法访问已释放的上下文实例。此错误的常见原因是释放从依赖项注入解析的上下文实例,然后尝试在应用程序的其他位置使用相同的上下文实例。如果在上下文实例上调用“Dispose”,或将其包装在 using 语句中,则可能会发生这种情况。如果使用依赖项注入,则应让依赖项注入容器负责处理上下文实例。

这有点奇怪,因为我修改了函数,除了查找对象并保存更改之外什么都不做......喜欢这个:

public async Task<InfoBool> MarkTransactionAsPaid(
    int paymentId, string pspReference, string receiptId)
{
    try
    {
        MoneyTransaction? foundtransaction =
            await _context.MoneyTransactions
                .Where(p => p.Id == paymentId)
                .Include(p =>p.User)
                .FirstOrDefaultAsync();

       ... // do stuff    
   
        await _context.SaveChangesAsync();

交易被发现很好,但是即使我删除了所有“做事”代码,SaveShanges也立即导致错误......

我在这里看到了对此的各种引用,大多数解决方案似乎都可以通过缺少“await”或函数在异步时返回 Void 来解决......我不认为这是这里的问题,也许围绕着我对依赖注入的理解(或缺乏)。

这是调用代码:

try
{
    if (receipt.result == "Success")
    {
        if (string.IsNullOrEmpty(receipt.originalReceiptId)) // Then this is a payment
        {
            var paymentId = int.Parse(receipt.consumer.yourConsumerReference);
            InfoBool res = await _accountsHelpers.MarkTransactionAsPaid(paymentId, receipt.yourPaymentReference, receipt.receiptId);
            if (!res.Success)
            {
... etc

在我的 accountsHelpers 中,我注入了 DBContext,如下所示:(略有简化)

public AccountsHelpers(
    IMapper mapper,
    RGDbContext context,
    IConfiguration settings, 
    IAzureHelpers azureHelpers)

    public AccountsHelpers(
    IMapper mapper,
    RGDbContext context,
    IConfiguration settings, 
    IAzureHelpers azureHelpers)
{
    _mapper = mapper;
    _context = context;
    _settings = settings;
    _logger = logger;
    _azureHelpers = azureHelpers;
}

在我的程序.cs中,并添加帐户助手,如下所示:

//AccountsHelpers
builder.Services.AddScoped<IAccountsHelpers, AccountsHelpers>();

以前,我在控制器中处理收据处理,从那里调用函数时,它工作正常。

InfoBool res = await _accountsHelpers.MarkTransactionAsPaid(
    paymentId,
    paymentResult.receipt.yourPaymentReference,
    paymentResult.receipt.receiptId);
    
if (!res.Success)...

我不清楚我在哪里调用“处置”,我确实想知道它是否可能是两个函数中的 try catch 块?但不要真正看到这一点。还想知道这是否是我设置 DI 的方式......

我现在已经通过将函数移回控制器来解决这个问题......但我想理解这一点,而且,代码对于控制器来说真的有点太重了。有什么想法吗?ProcessReceipt

C# 实体框架 依赖关系注入

评论

0赞 Brett JB 11/16/2023
感谢您“编辑”我的问题史蒂文......你有什么有用的补充吗?
0赞 Denis Micheal 11/16/2023
只是试图理解其中的逻辑,我看到您查询了一个事务并继续调用,但是对事务进行了哪些更改/修改?MarkTransactionAsPaidSaveChangesAsync
1赞 Steven 11/16/2023
@BrettJB:你的问题中一定缺少一些关键的细节,因为我看不出有什么理由从你的脚下处理掉。你能把你的问题变成一个最小的、可重复的例子吗?即一个包含重现问题的最少代码量的示例,但是一个我们(理想情况下)可以在本地复制/粘贴和运行的完全有效的程序吗?请在执行此操作时添加评论。DbContext
1赞 Svyatoslav Danyliv 11/17/2023
除了以下例外的常见情况:1) 在某个地方忘记了 2) 在处理上下文后重新调整了某些函数和物化对象。awaitIQueryable/IEnumerable
1赞 Steve Py 11/17/2023
调用 MarkTransactionAsPaid 的代码是什么?等待那个电话吗?您是否正在尝试使用任何并行化?系统中是否有任何代码正在释放任何 DbContext 实例,无论是注入的还是其他的?释放注入的 DbContext 的代码将是罪魁祸首,如果您有任何释放 DbContext 的代码行,我会在那里放置断点并在没有任何其他断点的情况下运行应用程序,以防释放潜在的共享实例。你展示的内容并不能解释问题,这意味着问题出在你意想不到的地方。

答: 暂无答案