He escrito una aplicación simple y cuando navego a mi página de edición aparece el siguiente error.
Microsoft.EntityFrameworkCore.Consulta[10100]
Se produjo una excepción al iterar sobre los resultados de una consulta para el tipo de contexto 'app.Models.ApplicationDbContext'.
System.ObjectDisposedException: no se puede acceder a un objeto desechado. Una causa común de este error es desechar un contexto que se resolvió a partir de la inyección de dependencia y luego intentar usar la misma instancia de contexto en otra parte de su aplicación. Esto puede ocurrir si está llamando a Dispose() en el contexto o envolviendo el contexto en una declaración de uso. Si está utilizando la inyección de dependencia, debe dejar que el contenedor de inyección de dependencia se encargue de desechar las instancias de contexto.
Parece que EF está demostrando una información útil que no puedo entender. La parte complicada de este error es que ocurre aleatoriamente cuando navego a la página de edición. A veces funciona, a veces falla al cargar algunas propiedades en Edit.cshtml pero aún funciona y, a veces, la aplicación se bloquea con el error proporcionado solo en mi consola. Otro hecho extraño es que no genera ningún error 500 o 5xx . Simplemente se bloquea y detiene la aplicación.
Aquí está mi contenido 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> Aquí está el método My Edit.cshtm.cs OnGet :
public async void OnGet(int id) { Book = await _db.Books.SingleOrDefaultAsync(x => x.Id == id); if(Book == null) { RedirectToPage("Index"); } } Estoy usando .Net Core 2.2.104
Además, cuando ejecuto el comando dotnet ef --version , genera Entity Framework Core .NET Command-line Tools 2.2.2-servicing-10034
Esto se debe a que su método devuelve el tipo async void . En general, cuando usa async void en su código, es una mala noticia porque:
Por lo tanto, devuelva async Task en lugar de un async void de su método de la siguiente manera:
public async Task OnGet(int id) { Book = await _db.Books.SingleOrDefaultAsync(x => x.Id == id); if(Book == null) { RedirectToPage("Index"); } }Para más detalles:
Lo que voy a publicar NO es la respuesta a esta pregunta en particular. Pero está relacionado, así que solo para ahorrarle dolor de cabeza a alguien, lo estoy publicando. Estaba encontrando este mismo error.
System.ObjectDisposedException: no se puede acceder a un objeto desechado. etc.
El siguiente era el código con el error (¿puedes verlo?):
[HttpGet("processs/oxxo-spei/ticket-email/{paymentIdx}")] public StatusCodeResult ProcessOxxoSpeiTicketEmailAsync(string paymentIdx) { var paymentId = paymentIdx.DecodeRef(); var response = _orderEngine.ProcessOxxoSpeiTicketEmailAsync(paymentId); return StatusCode(200); }El siguiente cambio lo arregló:
[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); }Sí, es cierto, había olvidado poner "aguardar" antes de una función que usaba un contexto de base de datos de EF Core. Agregar 'esperar' lo arregló. Es tan fácil perdérselo, especialmente si está cansado y no ha cumplido la fecha límite.
Esta es otra respuesta para quien va a leer este tema.
Traté de activar el método asnyc con javascript. Debido a eso, no se puede activar y, por lo tanto, el resultado no se calculó mediante el método asíncrono. Estaba devolviendo el objeto json para verlo así en dotnet core mvc.
return Json(_service.AsyncMethod(parameter));Mi IActionResult no es asíncrono, por lo que no puedo agregar "esperar". Solo agrego ".Result" y calcula el resultado.
return Json(_service.AsyncMethod(parameter).Result);Esto es lo que realmente funcionó para mí en una situación en la que recibía el mismo error que el anterior al intentar acceder a los datos en Startup.cs para ejecutar algunas funciones de creación de datos de inicio en la carga del servidor, en lugar de una acción específica del controlador:
IServiceScope scope = provider.CreateScope(); YourDbContext context = scope.ServiceProvider.GetRequiredService<YourDbContext>();En el método Configure de Startup.cs, con IServiceProvider incluido como parámetro:
public async void Configure(IApplicationBuilder app, IWebHostEnvironment env, IServiceProvider provider)Solo incluyo eso para cualquiera que quiera hacer lo mismo en Startup.cs.
Cree el objeto IServiceScopeFactory y la dependencia utilizada del objeto IServiceScopeFactory una vez que se deseche.
private readonly IServiceScopeFactory moserviceScopeFactory; private readonly InvoicesDataContext moInvoicesDataContext; public ABCController(InvoicesDataContext diInvoicesDataContext, IServiceScopeFactory serviceScopeFactory) { moInvoicesDataContext = diInvoicesDataContext; moserviceScopeFactory = serviceScopeFactory; }Mi objeto se ha eliminado después de ejecutar el código siguiente y quiero acceder al objeto después de ejecutar este código. Creé un objeto de IServiceScopeFactory y lo usé. y funcionando bien para mí.
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 TaskHas intentado...
async Task de la pila de llamadas en lugar de async void Después de una mirada cuidadosa a mi pila de llamadas, SaveChangeAsync en mi DbContext e hice una llamada para cambiar el comportamiento de cómo funciona async de forma predeterminada. Esto resultó en que mi contexto fuera desechado y todavía intentara acceder a él.
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);
omita ConfigureAwait(false)
await dispatcher.Dispatch(domainEvent);
ASP.NET Core no usa un [ SynchronizationContext ].( https://devblogs.microsoft.com/dotnet/configureawait-faq/ ).
Al usar las opciones ConfigureAwait(false) en una Task async , la tarea en ejecución no se reanudará en este contexto, sino en un subproceso de grupo de subprocesos. Esencialmente, al configurar esa llamada en await , cuando el hilo terminó de enviar los eventos , el contexto ya estaba eliminado.
Continúe revisando cada invocación de método/función desde el comienzo de su solicitud hasta el momento en que falla y vea si puede estar alterando el comportamiento predeterminado de async/await a través de ConfigureAwait(false) o un cambio de alteración similar.
Para obtener más información, recomiendo seguir este enlace de Stephen Cleary en su blog sobre async more.
RESPUESTA ACTUALIZADA CUANDO EL PROBLEMA NO ES UNA TAREA DE TIPO VOID La respuesta aceptada está bien si está utilizando un método anulado. Hay otro problema potencial con una solución simple si su método no es un vacío.
Verifique que el método de su controlador sea Tarea asíncrona si los métodos siguientes también son Tarea asíncrona. En mi caso, el problema fue el hecho de que no puse asíncrono en el método del controlador, pero los métodos de línea descendente eran tareas asíncronas.
¡Salud!