Я написал простое приложение, и когда я перехожу на свою страницу редактирования, появляется сообщение об ошибке ниже.
Microsoft.EntityFrameworkCore.Query[10100]
An exception occurred while iterating over the results of a query for context type 'app.Models.ApplicationDbContext'.
System.ObjectDisposedException: Cannot access a disposed object. A common cause of this error is disposing a context that was resolved from dependency injection and then later trying to use the same context instance elsewhere in your application. This may occur if you are calling Dispose() on the context, or wrapping the context in a using statement. If you are using dependency injection, you should let the dependency injection container take care of disposing context instances.
Кажется, EF доказывает полезную информацию, которую я не могу понять. Сложность этой ошибки в том, что она возникает случайным образом, когда я перехожу на страницу редактирования. Иногда это работает, иногда не удается загрузить некоторые свойства Edit.cshtml, но все еще работает, а иногда приложение вылетает с указанной ошибкой прямо в моей консоли. Еще один странный случай заключается в том, что он не генерирует ошибок 500 или 5xx. Он просто вылетает и останавливает приложение.
Вот мой 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.csOnGet метод:
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





Это из-за типа возврата вашего метода 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");
}
}
Больше подробностей:
У меня тоже есть эта проблема, но я нигде не использую async void, всегда использую async Task
@brando Тогда проблема кроется где-то в вашем коде. Пожалуйста, задайте отдельный вопрос с вашим кодом. Надеюсь, я или кто-то другой поможет вам.
Я обнаружил свою ошибку. Очень расстраивает, пока не поймешь простое решение
Большое спасибо. Я рвал на себе волосы и начинал думать, что уровень бесплатного пользования Azure — отстой, когда на самом деле проблема снова возникла перед ПК.
Заранее спасибо, но как я могу вызвать метод "public async Task OnGet()" из вызова потока??
@SelimReza await OnGet()
@TanvirArjel, вы показали нормальный процесс вызова, но я хочу узнать процесс с помощью вызова Thread.
@SelimReza Пожалуйста, посмотрите здесь: Асинхронное программирование с помощью async и await
То, что я собираюсь опубликовать, НЕ является ответом на этот конкретный вопрос. Но это связано, поэтому я публикую его, чтобы избавить кого-то от головной боли. Я столкнулся с этой же ошибкой
System.ObjectDisposedException: Cannot access a disposed object. etc
Ниже был код с ошибкой (вы его видите?):
[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. Добавление «ожидания» исправило это. Так легко пропустить это, особенно если вы устали и у вас нет времени.
Спасибо, чувак, у меня был контроллер, который использовал неасинхронный метод, а затем изменил метод службы, который он использовал, на асинхронный, и никогда не добавлял метод aysnc или ожидание на стороне контроллера, черт возьми........
Я также не использовал асинхронность в своем методе контроллера, и я чувствую себя полным идиотом, боровшимся с этим два дня. Иногда нужно просто встать и прогуляться. Спасибо, что опубликовали это.
Просто чтобы добавить, короче говоря, возврат задачи решит проблему и убедитесь, что экземпляр объекта не удален.
Разве это не будет подхвачено буквально в любом редакторе...?
@fullStackChris Я думаю, что сейчас
Я столкнулся с этой проблемой сегодня, с DbContext, я думаю, что это гораздо больше связано с тем, как и когда внедряются классы.
Это еще один ответ для тех, кто будет читать эту тему.
Я попытался запустить метод asnyc с помощью javascript. Из-за этого он не может запускаться, поэтому результат не рассчитывается асинхронным методом. Я возвращал объект json для просмотра в dotnet core mvc.
return Json(_service.AsyncMethod(parameter));
Мой IActionResult не является асинхронным, поэтому я не могу добавить «ожидание». Я просто добавляю ".Result" и вычисляю результат.
return Json(_service.AsyncMethod(parameter).Result);
Вот что на самом деле сработало для меня в ситуации, когда я получал ту же ошибку, что и выше, при попытке доступа к данным в Startup.cs для запуска некоторых функций построения данных запуска при загрузке сервера, а не определенного действия контроллера:
IServiceScope scope = provider.CreateScope();
YourDbContext context = scope.ServiceProvider.GetRequiredService<YourDbContext>();
В методе Configure файла Startup.cs с IServiceProvider, включенным в качестве параметра:
public async void Configure(IApplicationBuilder app, IWebHostEnvironment env, IServiceProvider provider)
Просто включите это для всех, кто хочет сделать то же самое в Startup.cs.
Создайте объект 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;
}
Как этот код (с плохим отступом) отвечает на вопрос? Правильный ответ уже дан, и он прост очень. Даже при создании области async void будет проблема, так что это ничего не решает.
async Task конверсийВы пытались...
async Task вместо async voidПосле внимательный взгляд в моем стеке вызовов я переопределил метод SaveChangeAsync в моем DbContext и сделал вызов, чтобы изменить поведение того, как 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)
await dispatcher.Dispatch(domainEvent);
ASP.NET Core не использует [SynchronizationContext].(https://devblogs.microsoft.com/dotnet/configureawait-faq/).
При использовании ConfigureAwait(false)опции для asyncTask выполнение задачи возобновится не в этом контексте, а вместо этого в потоке пула потоков. По сути, настроив этот вызов await, когда поток завершил отправку событий, контекст был удален уже.
Продолжать просматривает вызов каждый метод/функция от начало вашего запроса до момента, когда он терпит неудачу, и смотрит, можете ли вы изменить поведение по умолчанию async/await через ConfigureAwait(false) или подобное изменяющее изменение.
Для получения дополнительной информации я настоятельно рекомендую по этой ссылке Стивена Клири в его блоге о async больше.
Можете ли вы уточнить, какую проблему это создало? Тот факт, что продолжение возобновляется в потоке пула потоков, не должен позволять контексту быть удаленным до его завершения (если вы не ожидаете своего вызова SaveChangesAsync() верхнего уровня перед удалением контекста, и в этом случае это будет функционально эквивалентен async void). Я чувствую, что в истории должно быть больше, чем отражено в ваших фрагментах кода, например, использование полей [ThreadStatic] или Task.Run() или что-то в этом роде.
@JeremyTodd Если я правильно помню, в конвейере запросов весь, который я использовал для построения этого ответа, не было ни ThreadStatic, ни Task.Runs и т. д., ни чего-либо другого, кроме стандартного await/async. По причинам, которые я пытался понять из документации, на которую я ссылался в своем ответе, кажется, что вызов async к SaveChangesAsync, который имеет асинхронный вызов ConfigureAwait к диспетчеру, вызвал эту проблему, потому что это было единственное внесенное изменение, которое вызвало ошибку полностью пропадать. Это происходило последовательно в режиме отладки/релиза.
ОБНОВЛЕННЫЙ ОТВЕТ, КОГДА ПРОБЛЕМА НЕ ЯВЛЯЕТСЯ ЗАДАЧЕЙ ТИПА ПУСТОЙ Принятый ответ подходит, если вы используете аннулированный метод. Есть еще одна потенциальная проблема с простым решением, если ваш метод не пустой.
Убедитесь, что ваш метод контроллера является асинхронной задачей, если методы ниже по линии также являются асинхронной задачей. В моем случае проблема заключалась в том, что я не поставил асинхронный метод контроллера, а нижестоящие методы были асинхронными Task.
Ваше здоровье!
Большое спасибо за это
ЗОЛОТОЙ ОТВЕТ!!!!! :)
Спас одну ночь!
У меня была такая же проблема, большое спасибо за это. Я провел глобальный поиск и нашел еще пару асинхронных пустот, которые я заменил асинхронной задачей, чтобы избежать потенциальных проблем в будущем.
прочитать этот статья