Saltar al contenido

Controlador ASP.NET: un módulo asincrónico o controlador completado mientras una operación asincrónica aún estaba pendiente

Estate atento porque en este escrito vas a encontrar la solución que buscas.Esta noticia ha sido analizado por nuestros especialistas para asegurar la calidad y veracidad de nuestro post.

Solución:

En Async Void, ASP.Net y Count of Outstanding Operations, Stephan Cleary explica la raíz de este error:

Históricamente, ASP.NET ha admitido operaciones asincrónicas limpias desde .NET 2.0 a través del patrón asincrónico basado en eventos (EAP), en el que los componentes asincrónicos notifican al SynchronizationContext su inicio y finalización.

lo que pasa es que estas disparando DownloadAsync dentro de tu constructor de clase, donde dentro de ti await en la llamada http asíncrona. Esto registra la operación asíncrona con el ASP.NET SynchronizationContext. Cuando tu HomeController regresa, ve que tiene una operación asincrónica pendiente que aún no se ha completado, y es por eso que genera una excepción.

Si eliminamos task = DownloadAsync(); del constructor y colóquelo en el método Index, funcionará bien sin los errores.

Como expliqué anteriormente, eso se debe a que ya no tiene una operación asincrónica pendiente mientras regresa del controlador.

Si usamos otro cuerpo de DownloadAsync(), espere el regreso
Task.Factory.StartNew(() => Thread.Sleep(3000); return "Give me an
error"; );
funcionará correctamente.

Eso es porque Task.Factory.StartNew hace algo peligroso en ASP.NET. No registra la ejecución de tareas con ASP.NET. Esto puede conducir a casos extremos en los que se ejecuta un reciclaje de grupo, ignorando por completo su tarea en segundo plano, lo que provoca un aborto anormal. Es por eso que debe usar un mecanismo que registre la tarea, como HostingEnvironment.QueueBackgroundWorkItem.

Por eso no es posible hacer lo que estás haciendo, de la forma en que lo estás haciendo. Si realmente desea que esto se ejecute en un subproceso en segundo plano, en un estilo de “dispara y olvida”, use cualquiera HostingEnvironment (si está en .NET 4.5.2) o BackgroundTaskManager. Tenga en cuenta que al hacer esto, está utilizando un subproceso de grupo de subprocesos para realizar operaciones de E/S asíncronas, que es redundante y exactamente con lo que es asíncrono. async-await intentos de superación.

ASP.NET considera ilegal iniciar una “operación asíncrona” vinculada a su SynchronizationContext y devolver un ActionResult antes de que se completen todas las operaciones iniciadas. Todos async Los métodos se registran a sí mismos como “operaciones asíncronas”, por lo que debe asegurarse de que todas las llamadas que se unen a ASP.NET SynchronizationContext completar antes de devolver un ActionResult.

En su código, regresa sin asegurarse de que DownloadAsync() ha corrido hasta completarse. Sin embargo, guarda el resultado en el task miembro, por lo que asegurarse de que esté completo es muy fácil. Simplemente pon await task en todos sus métodos de acción (después de sincronizarlos) antes de regresar:

public async Task IndexAsync()

    try
    
        return View();
    
    finally
    
        await task;
    

EDITAR:

En algunos casos, es posible que deba llamar a un async método que no debe completarse antes de volver a ASP.NET. Por ejemplo, es posible que desee inicializar de forma diferida una tarea de servicio en segundo plano que debería continuar ejecutándose después de que se complete la solicitud actual. Este no es el caso del código del OP porque el OP quiere que la tarea se complete antes de regresar. Sin embargo, si necesita comenzar y no esperar una tarea, hay una forma de hacerlo. Simplemente debes usar una técnica para “escapar” de la corriente SynchronizationContext.Current.

  • (no recomendado) Una característica de Task.Run() es escapar del contexto de sincronización actual. Sin embargo, la gente recomienda no usar esto en ASP.NET porque el grupo de subprocesos de ASP.NET es especial. Además, incluso fuera de ASP.NET, este enfoque da como resultado un cambio de contexto adicional.

  • (recomendado) Una forma segura de escapar del contexto de sincronización actual sin forzar un cambio de contexto adicional o molestar inmediatamente al grupo de subprocesos de ASP.NET es establecer SynchronizationContext.Current a nullllama a tu async y luego restaurar el valor original.

Me encontré con un problema relacionado. Un cliente está utilizando una interfaz que devuelve una tarea y se implementa con async.

En Visual Studio 2015, el método de cliente que es asíncrono y que no usa la palabra clave await al invocar el método no recibe advertencia ni error, el código se compila sin problemas. Una condición de carrera se promociona a producción.

Reseñas y valoraciones del post

Si estás de acuerdo, puedes dejar un post acerca de qué le añadirías a este tutorial.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *