无法访问已处置的对象。导致此错误的常见原因是处理上下文

时间:2019-04-05 21:27:38

标签: .net entity-framework .net-core entity-framework-core

我已经编写了一个简单的应用程序,当我导航到编辑页面时,将弹出以下错误消息。

  

Microsoft.EntityFrameworkCore.Query [10100]

     

遍历上下文类型'app.Models.ApplicationDbContext'的查询结果时发生异常。

     

System.ObjectDisposedException:无法访问已处置的对象。导致此错误的常见原因是,处理从依赖项注入中解决的上下文,然后稍后尝试在应用程序中的其他位置使用相同的上下文实例。如果在上下文上调用Dispose()或将上下文包装在using语句中,则可能会发生这种情况。如果您正在使用依赖项注入,则应让依赖项注入容器来处理上下文实例。

似乎EF证明了我无法理解的有用信息。该错误的棘手部分是,当我导航到编辑页面时,它会随机发生。有时它可以工作,有时它无法加载Edit.cshtml上的某些属性,但仍然可以工作,有时应用程序崩溃,仅在我的控制台中提供了错误。另一个奇怪的情况是它不会产生任何5005xx错误。它只是崩溃并停止应用程序。

这是我的Edit.cshtml内容:

@page
@model EditModel
@{
    ViewData["Title"] = "Edit Book";
}

<h2>Edit Book</h2>

<div class="row justify-content-center">
    <div class="col-md-6">
        <form method="post" class="form-border">
            <div asp-validation-summary="All" class="validation-container alert alert-danger"></div>
            <div class="form-group">
                <label asp-for="Book.Name"></label>
                <input asp-for="Book.Name" class="form-control" />
                <span class="form-text text-danger" asp-validation-for="Book.Name"></span>
            </div>
            <div class="form-group">
                <label asp-for="Book.Description"></label>
                <input asp-for="Book.Description" class="form-control" />
            </div>
            <div class="form-group">
                <label asp-for="Book.Author"></label>
                <input asp-for="Book.Author" class="form-control" />
            </div>
            <input asp-for="Book.Id" type="hidden">
            <button type="submit" class="btn btn-primary">Update</button>
            <a asp-page="Index" class="btn btn-success">Back To List</a>
        </form>
    </div>
</div>

这是我的Edit.cshtm.cs OnGet方法:

public async void OnGet(int id)
{
    Book = await _db.Books.SingleOrDefaultAsync(x => x.Id == id);

    if(Book == null)
    {
        RedirectToPage("Index");
    }
}

我正在使用.Net Core 2.2.104

另外,当我运行命令dotnet ef --version时,它会生成Entity Framework Core .NET Command-line Tools 2.2.2-servicing-10034

6 个答案:

答案 0 :(得分:4)

这是因为您的方法返回类型为async void。通常,当您在代码中使用async void时,这是个坏消息,因为:

  • 您不能等待其完成
  • 任何未处理的异常都会终止您的进程(哎呀!)

因此从您的方法中返回async Task而不是async void,如下所示:

public async Task OnGet(int id)
{
    Book = await _db.Books.SingleOrDefaultAsync(x => x.Id == id);

    if(Book == null)
    {
       RedirectToPage("Index");
    }
}

有关更多详细信息:

答案 1 :(得分:0)

我要发布的内容不是此特定问题的答案。但这是相关的,所以只是为了节省我发布的头疼。我遇到了同样的错误

  

System.ObjectDisposedException:无法访问已处置的对象。等

以下是带有错误的代码(您可以看到它):

[HttpGet("processs/oxxo-spei/ticket-email/{paymentIdx}")]
        public StatusCodeResult ProcessOxxoSpeiTicketEmailAsync(string paymentIdx)
        {
            var paymentId = paymentIdx.DecodeRef();
            
            var response = _orderEngine.ProcessOxxoSpeiTicketEmailAsync(paymentId);

            return StatusCode(200);
        }

以下更改已解决:

[HttpGet("processs/oxxo-spei/ticket-email/{paymentIdx}")]
        public async Task<StatusCodeResult> ProcessOxxoSpeiTicketEmailAsync(string paymentIdx)
        {
            var paymentId = paymentIdx.DecodeRef();
            
            var response = await _orderEngine.ProcessOxxoSpeiTicketEmailAsync(paymentId);
                       // ^^^^I HAD FORGOTTEN TO PUT AWAIT
            return StatusCode(200);
        }

是的,我忘记了在使用EF Core dbcontext的函数前加上“ await”。添加“等待”修复了它。非常容易错过它,特别是如果您累了并且在截止日期之前。

答案 2 :(得分:0)

在尝试访问Startup.cs中的数据以在服务器负载下运行某些启动数据构建功能而不是特定的Controller动作时遇到与上述相同的错误时,这是​​对我真正起作用的方法:

        IServiceScope scope = provider.CreateScope();
        YourDbContext context = scope.ServiceProvider.GetRequiredService<YourDbContext>();

在Startup.cs的Configure方法中,以IServiceProvider作为参数:

public async void Configure(IApplicationBuilder app, IWebHostEnvironment env, IServiceProvider provider)

对于那些想要在Startup.cs中进行相同操作的人来说,就包括在内。

答案 3 :(得分:0)

async Task 次转化的替代解决方案


你已经试过了...

  • 使调用堆栈中的所有方法async Task 而不是async void

在仔细查看我的调用堆栈后仔细查看后,我覆盖了 SaveChangeAsync 中的 DbContext 方法,并进行了调用以更改 {{1 }} 默认运行。这导致我的上下文被处理并仍在尝试访问它。


为简洁起见省略了一些代码

async

问题方式

public override async Task<int> SaveChangesAsync(CancellationToken cancellationToken = default) { int result = await base.SaveChangesAsync(cancellationToken); // ignore events if no dispatcher provided if (dispatcher is null) return result; // dispatch events only if save was successful await DispatchEventsIfSaveSuccessful(); return result; } private async Task DispatchEventsIfSaveSuccessful() { var entitiesWithEvents = ChangeTracker .Entries<Entity>() .Select(e => e.Entity) .Where(e => e.Events.Any()) .ToArray(); ... foreach (var entity in entitiesWithEvents) { var events = entity.Events.ToArray(); entity.Events.Clear(); foreach (var domainEvent in events) { await dispatcher.Dispatch(domainEvent).ConfigureAwait(false); } } }

解决办法

省略 await dispatcher.Dispatch(domainEvent).ConfigureAwait(continueOnCapturedContext: false);

ConfigureAwait(false)

说明

ASP.NET Core 不使用 [await dispatcher.Dispatch(domainEvent);].(https://devblogs.microsoft.com/dotnet/configureawait-faq/).

SynchronizationContext ConfigureAwait(false) 上使用 async options 时,正在执行的任务不会在此上下文中恢复,而是在线程池线程上恢复。基本上通过配置 Task 调用,当 thread finished dispatching the events 时,上下文已经被释放。

建议

继续查看每个方法/函数调用,从请求开始一直到失败 strong> 并查看您是否可能通过 await 或类似的更改更改 async/await 的默认行为。

要了解更多信息,我强烈推荐 Stephen Cleary 在他的博客中撰写的 following this link,关于 ConfigureAwait(false) 的更多内容。

答案 4 :(得分:-1)

这是谁会读这个话题的答案。

我试图用javascript触发asnyc方法。因此,它无法触发,因此结果不是通过异步方法计算的。我正在返回json对象,以在dotnet core mvc中进行查看。

return Json(_service.AsyncMethod(parameter));

我的IActionResult不是异步的,所以我不能添加“ await”。我只添加“ .Result”,它就会计算结果。

return Json(_service.AsyncMethod(parameter).Result);

答案 5 :(得分:-1)

创建 IServiceScopeFactory 对象并在 IServiceScopeFactory 对象释放后使用依赖项。

private readonly IServiceScopeFactory moserviceScopeFactory;
private readonly InvoicesDataContext moInvoicesDataContext;
public ABCController(InvoicesDataContext diInvoicesDataContext, IServiceScopeFactory serviceScopeFactory)
        {
            moInvoicesDataContext = diInvoicesDataContext;
            moserviceScopeFactory = serviceScopeFactory;
        }

我的对象在执行以下代码后已被处理,我想在执行此代码后访问对象。我已经从 IServiceScopeFactory 创建了对象并使用了。并且对我来说工作正常。

public async Task<int> generateInvoice()
            {
                List<Guid> loSentId = new List<Guid>();
                Invoices loDataContext = new Invoices(moInvoicesDataContext);
                List<Invoices> loInvoices = loInvoiceDataContext.get("", null, "", null, null, 1, "1", "asc", 1, 5);
    
                bool lblIsSuccess = await loSystemEmails.sendInvoice(loInvoice.stInvoiceNumber, loInvoice.stCompanyEmail, string.Empty, loInvoice.stCompanyName, GetFolderPath.loRootPath + lsSystemFilePath, "1");
                                    if (lblIsSuccess)
                                    {
                                        loSentInvoiceId.Add(loInvoice.unCompanyInvoiceId);
    
                                        

using (var scope = moserviceScopeFactory.CreateScope())
                                        {
                                            var context = scope.ServiceProvider.GetRequiredService<InvoicesDataContext>();

    
                                            int liSuccess = new Invoices(context).SaveData(Convert.ToString(loInvoice.unCompanyInvoiceId), 2, Guid.Empty, "New Zealand Standard Time", "+13:00"); //2 = Sent
                                        }
                                    }
                return loSentInvoiceId != null && loSentInvoiceId.Count > 0 ? loSentInvoiceId.Count : 0;
            }