Saltar al contenido

Usar HttpContext.Current en WebApi es peligroso debido a async

Nuestro team de trabajo ha estado mucho tiempo buscando para dar solución a tu pregunta, te ofrecemos la soluciones así que deseamos que te sea de mucha ayuda.

Solución:

HttpContext.Current obtiene el contexto actual por Thread (investigué la implementación directamente).

Sería más correcto decir que HttpContext se aplica a un hilo; o un hilo “entra” en el HttpContext.

No es posible usar HttpContext.Current dentro de una tarea asíncrona, porque puede ejecutarse en otro subproceso.

De nada; el comportamiento predeterminado de async/await se reanudará en un hilo arbitrario, pero ese hilo entrará en el contexto de solicitud antes de reanudar su async método.


Él key a este es el SynchronizationContext. Tengo un artículo de MSDN sobre el tema si no está familiarizado con él. UN SynchronizationContext define un “contexto” para una plataforma, siendo los más comunes los contextos de la interfaz de usuario (WPF, WinPhone, WinForms, etc.), el contexto del grupo de subprocesos y el contexto de solicitud de ASP.NET.

El contexto de solicitud de ASP.NET administra HttpContext.Current así como algunas otras cosas como la cultura y la seguridad. Los contextos de la interfaz de usuario están estrechamente asociados con un solo hilo (la Subproceso de interfaz de usuario), pero el contexto de solicitud de ASP.NET no está vinculado a un subproceso específico. Sin embargo, solo permitirá un hilo en el contexto de la solicitud. a la vez.

La otra parte de la solución es cómo async y await trabaja. Yo tengo un async intro en mi blog que describe su comportamiento. En resumen, await por defecto capturará el contexto actual (que es SynchronizationContext.Current a menos que sea null), y use ese contexto para reanudar el async método. Asi que, await está capturando automáticamente el ASP.NET SynchronizationContext y reanudará la async método dentro de ese contexto de solicitud (preservando así la cultura, la seguridad y la HttpContext.Current).

Si tu awaitConfigureAwait(false)entonces estás diciendo explícitamente await para no capturar el contexto.

Tenga en cuenta que ASP.NET tuvo que cambiar su SynchronizationContext trabajar limpiamente con async/await. Debe asegurarse de que la aplicación esté compilada con .NET 4.5 y también se dirija explícitamente a 4.5 en su web.config; este es el valor predeterminado para los proyectos nuevos de ASP.NET 4.5, pero debe configurarse explícitamente si actualizó un proyecto existente de ASP.NET 4.0 o anterior.

Puede asegurarse de que estas configuraciones sean correctas ejecutando su aplicación contra .NET 4.5 y observando SynchronizationContext.Current. Si esto es AspNetSynchronizationContext, entonces eres bueno; si es LegacyAspNetSynchronizationContextentonces la configuración es incorrecta.

Siempre que la configuración sea correcta (y esté utilizando ASP.NET 4.5 AspNetSynchronizationContext), entonces puede usar con seguridad HttpContext.Current después de un await sin preocuparte por eso.

Estoy usando una API web, que usa la metodología async/await.

también usando

1) HttpContext.Current.Server.MapPath
2) System.Web.HttpContext.Current.Request.ServerVariables

Esto funcionó bien durante una buena cantidad de tiempo y se rompió repentinamente sin cambiar el código.

Pasando mucho tiempo volviendo a versiones anteriores anteriores, encontré el que faltaba key causa el problema.

< httpRuntime targetFramework="4.5.2"  /> under system.web

No soy un experto técnicamente. Pero sugiero agregar el key a su configuración web y darle un VAMOS.

Encontré un artículo muy bueno que describe exactamente este problema: http://byterot.blogspot.cz/2012/04/aspnet-web-api-series-part-3-async-deep.html?m=1

El autor investigó profundamente cómo se llama al método ExecuteAsync en el marco WebApi y llegó a esta conclusión:

Las acciones de la API web de ASP.NET (y todos los métodos de canalización) se llamarán de forma asincrónica solo si devuelve una tarea o una tarea. Esto puede parecer obvio, pero ninguno de los métodos de canalización con el sufijo Async se ejecutará en sus propios subprocesos. Usar Async general podría ser un nombre inapropiado. [UPDATE: ASP.NET team indeed have confirmed that the Async is used to denote methods that return Task and can run asynchronously but do not have to]

Lo que entendí del artículo es que los métodos de acción se llaman sincrónicamente, pero es la decisión de la persona que llama.

Creé una pequeña aplicación de prueba para este propósito, algo como esto:

public class ValuesController : ApiController

    public object Get(string clientId, string specialValue)
    
        HttpRequest staticContext = HttpContext.Current.Request;
        string staticUrl = staticContext.Url.ToString();

        HttpRequestMessage dynamicContext = Request;
        string dynamicUrl = dynamicContext.RequestUri.ToString();

        return new one = staticUrl, two = dynamicUrl;
    

y una versión asíncrona que regresa async Task

Traté de hacer un pequeño ataque de DOS con jquery y no pude determinar ningún problema hasta que usé await Task.Delay(1).ConfigureAwait(false);lo cual es obvio que fallaría.

Lo que saqué del artículo es que el problema es muy complicado y el cambio de subproceso puede ocurrir cuando se usa el método de acción asíncrono, por lo que definitivamente es NO una buena idea usar HttpContext.Current en cualquier parte del código llamado desde los métodos de acción. Pero como el controlador se crea sincrónicamente, usar HttpContext.Current en el constructor y también en la inyección de dependencia está bien.

Cuando alguien tenga otra explicación a este problema por favor corríjame ya que este problema es muy complicado y todavía no estoy 100% convencido.

descargo de responsabilidad:

  • Ignoro por ahora el problema de Web-Api autohospedado sin IIS, donde HttpContext.Current probablemente no funcionaría de todos modos. Ahora confiamos en IIS.

Si te gustó nuestro trabajo, tienes la habilidad dejar un ensayo acerca de qué te ha impresionado de esta división.

¡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 *

Respuestas a preguntas comunes sobre programacion y tecnología