¿Cómo obtengo un objeto HttpContext de HttpContextBase en ASP.NET MVC 1?

155

Estoy trabajando con algunas herramientas independientes de WebForms / MVC, y necesito obtener una instancia de HttpContextuna referencia dada a un HttpContextBaseobjeto. No puedo usar HttpContext.Currentporque necesito que esto funcione también de forma asíncrona ( HttpContext.Currentregresa nulldurante una solicitud asincrónica). Soy consciente HttpContextWrapper, pero va por el camino equivocado.

Daniel Schaffer
fuente

Respuestas:

250

La forma más simple es obtener la aplicación ApplicationInstance, y usar su Contextpropiedad:

// httpContextBase is of type HttpContextBase
HttpContext context = httpContextBase.ApplicationInstance.Context;

(gracias a Ishmael Smyrnow que notó esto en los comentarios)

Respuesta original:

Puede hacerlo, especialmente si la HttpContextBaseinstancia que le han entregado es de tipo HttpContextWrapperen tiempo de ejecución. El siguiente ejemplo ilustra cómo puede hacer esto. Supone que tiene un método llamado Fooque acepta el contexto como HttpContextBasepero luego necesita llamar a un método en un ensamblado de terceros (que puede que no tenga la suerte de modificar) que espera que el contexto se escriba como HttpContext.

void Foo(HttpContextBase context) 
{
    var app = (HttpApplication) context.GetService(typeof(HttpApplication));
    ThirdParty.Bar.Baz(app.Context);
}

// Somewhere in assembly and namespace ThirdParty,
// in a class called Bar, there is Baz expecting HttpContext:

static void Baz(HttpContext context) { /* ... */ }

HttpContextBasetiene un método llamado GetServicecomo resultado del soporte IServiceProvider. La GetServiceanulación de HttpContextWrapperdelegados a la GetServiceimplementación de la HttpContextinstancia envuelta . La GetServiceaplicación de la HttpContextque permite la consulta de los sospechosos habituales, como HttpApplication, HttpRequest, HttpResponsey así sucesivamente. Sucede que HttpApplicationtiene una propiedad llamada Context y que devuelve una instancia de HttpContext. Entonces uno llega a la HttpContextinstancia envuelta preguntando HttpContextBasepor HttpApplicationvía GetServiceseguido de leer la Contextpropiedad de la HttpApplicationinstancia devuelta .

A diferencia HttpContextBase, GetServiceno aparece como un miembro público de, HttpContextpero eso se debe a que HttpContextimplementa la IServiceProvider.GetServiceexplicidad mientras HttpContextBaseque no lo hace.

Tenga en cuenta que Fooya no es comprobable porque se basa en poder desenvolver el subyacente HttpContextdurante la prueba y, en primer lugar, es casi imposible falsificarlo. El punto de esta respuesta, sin embargo, es abordar la pregunta, "¿Cómo obtengo un objeto HttpContext de HttpContextBase?", Literalmente . La técnica ilustrada es útil en aquellas situaciones en las que te encuentras intercalado entre componentes que no necesariamente tienes el lujo de modificar.

Atif Aziz
fuente
3
Respuesta muy interesante, solo la utilicé en MVC para pasar el HttpContext de un filtro de error a ELMAH para el registro.
Chris Marisic
1
buena respuesta, ¿apuesto a que tomó un poco de investigación? :)
longhairedsi
¡gran respuesta! Lo utilicé especialmente en mi controlador Elmah
Alexander Beletsky
36
Con un HttpContextBase, ¿no podrías llamar context.ApplicationInstance.Context?
Ismael Smyrnow
@IshmaelSmyrnow Maldición, no sé cómo me perdí eso entre todas las Http*Basevariaciones devueltas por HttpContextBase. : P Actualizaré la respuesta.
Atif Aziz
32

Usted puede,

var abstractContext = new System.Web.HttpContextWrapper(System.Web.HttpContext.Current);
Marc Chouteau
fuente
16
-1 esta es la manera incorrecta, te da la Base cuando tienes el Contexto, no al revés.
Chris Marisic
14

No puedes

El propósito de HttpContextBasees abstraer la dependencia de la HttpContextclase concreta . Si bien puede contener un contenido concreto HttpContext (como es el caso httpContextWrapper) , otras implementaciones pueden no tener absolutamente nada que ver HttpContext.

Su mejor opción es definir una Fábrica de abstractos personalizada que pueda obtener una HttpContextBasepara usted, ya que siempre puede envolver un concreto HttpContexten una HttpContextWrapper.

Mark Seemann
fuente
13
Esto, por cierto, se hizo horriblemente: entiendo que quiero tener una configuración para pruebas unitarias y entiendo capas de abstracción, pero ¿qué se supone que debes hacer cuando quieres usar las clases ASP.NET existentes que esperan un HttpContext? (como msdn.microsoft.com/en-us/library/… )
marzo
Sí, para probar las IHttpHandlerimplementaciones, terminas teniendo que poner un número de abstracciones en (Contenedores de respuesta) solo para tus pruebas unitarias, lo que no se siente bien pero termina siendo la única opción.
Chris S