Wie erhalte ich ein HttpContext-Objekt von HttpContextBase in ASP.NET MVC 1?

154

Ich arbeite mit einigen WebForms / MVC-agnostischen Tools und muss eine Instanz HttpContexterhalten, die einen Verweis auf ein HttpContextBaseObjekt enthält. Ich kann nicht verwenden , HttpContext.Currentweil ich brauche dies auch asynchron zu arbeiten ( HttpContext.Currentkehrt nullwährend einer asynchronen Anfrage). Ich bin mir dessen bewusst HttpContextWrapper, gehe aber den falschen Weg.

Daniel Schaffer
quelle

Antworten:

249

Am einfachsten ist es, die Anwendung ApplicationInstanceabzurufen und ihre ContextEigenschaft zu verwenden:

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

(Danke an Ishmael Smyrnow, der dies in den Kommentaren vermerkt hat)

Ursprüngliche Antwort:

Dies ist insbesondere dann möglich, wenn die übergebene HttpContextBaseInstanz HttpContextWrapperzur Laufzeit vom Typ ist . Das folgende Beispiel zeigt, wie Sie dies tun können. Angenommen, Sie haben eine Methode namens Foo, die den Kontext als akzeptiert HttpContextBase, dann aber eine Methode in einer Assembly eines Drittanbieters aufrufen muss (die Sie möglicherweise nicht ändern können), die erwartet, dass der Kontext als eingegeben wird 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) { /* ... */ }

HttpContextBasehat eine Methode GetServiceals Ergebnis der Unterstützung aufgerufen IServiceProvider. Das GetServiceÜberschreiben von HttpContextWrapperDelegaten zur GetServiceImplementierung der umschlossenen HttpContextInstanz. Die GetServiceImplementierung HttpContextermöglicht es Ihnen , zu Abfrage für üblich Verdächtigen wie HttpApplication, HttpRequest, HttpResponseund so weiter. Es ist einfach so, dass HttpApplicationes eine Eigenschaft namens Context hat, die eine Instanz von zurückgibt HttpContext. Man gelangt also zur umschlossenen HttpContextInstanz, indem man HttpContextBasenach HttpApplicationvia fragt und GetServiceanschließend die ContextEigenschaft der zurückgegebenen HttpApplicationInstanz liest .

Im Gegensatz zu HttpContextBase, GetServiceerscheint nicht als ein öffentliches Mitglied , HttpContextaber das ist , weil HttpContextGeräte IServiceProvider.GetServiceexplicity während HttpContextBasenicht.

Denken Sie daran, dass dies Foonicht mehr testbar ist, da es darauf ankommt, dass der Basiswert HttpContextwährend des Tests ausgepackt werden kann und dass es nahezu unmöglich ist, ihn zu fälschen / zu stummeln . Der Sinn dieser Antwort besteht jedoch darin, die Frage „Wie erhalte ich ein HttpContext-Objekt von HttpContextBase?“ Wörtlich zu beantworten . Die dargestellte Technik ist in Situationen nützlich, in denen Sie sich zwischen Komponenten befinden, für deren Modifizierung Sie nicht unbedingt den Luxus haben.

Atif Aziz
quelle
3
Sehr interessante Antwort, habe es selbst in MVC verwendet, um den HttpContext von einem Fehlerfilter zur Protokollierung an ELMAH zu übergeben.
Chris Marisic
1
nette Antwort, Wette, das hat ein bisschen gegraben? :)
langhaarig
gute Antwort! Ich habe das besonders in meinem Elmah to MVC-Controller verwendet. Github.com/alexanderbeletsky/elmah.mvc.controller/blob/master/…
Alexander Beletsky
35
Könnten Sie mit einer HttpContextBase nicht anrufen context.ApplicationInstance.Context?
Ishmael Smyrnow
@IshmaelSmyrnow Verdammt, nicht, wie ich das unter all den Http*BaseVariationen verpasst habe, die von zurückgegeben wurden HttpContextBase. : P Ich werde die Antwort aktualisieren.
Atif Aziz
32

Sie können,

var abstractContext = new System.Web.HttpContextWrapper(System.Web.HttpContext.Current);
Marc Chouteau
quelle
16
-1 Dies ist der falsche Weg. Dies gibt Ihnen die Basis, wenn Sie den Kontext haben, nicht umgekehrt.
Chris Marisic
14

Das kannst du nicht.

Der ganze Zweck von HttpContextBaseist es, die Abhängigkeit von der konkreten HttpContextKlasse zu abstrahieren . Während es einen konkreten Inhalt enthalten kann HttpContext (wie dies bei der Fall ist httpContextWrapper) , haben andere Implementierungen möglicherweise absolut nichts damit zu tun HttpContext.

Am besten definieren Sie eine benutzerdefinierte abstrakte Fabrik, die eine HttpContextBasefür Sie erhalten kann, da Sie jederzeit einen Beton HttpContextin eine einwickeln können HttpContextWrapper.

Mark Seemann
quelle
12
Dies wurde übrigens schrecklich getan - ich verstehe, dass ich ein Setup für Komponententests haben möchte, und ich verstehe Abstraktionsebenen -, aber WTH sollten Sie tun, wenn Sie vorhandene ASP.NET-Klassen verwenden möchten, die einen HttpContext erwarten? (wie msdn.microsoft.com/en-us/library/… )
März
Ja, um IHttpHandlerImplementierungen zu testen , müssen Sie nur für Ihre Unit-Tests eine ganze Reihe von Abstraktionen in (Response-Wrapper) einfügen, was sich nicht richtig anfühlt, aber letztendlich die einzige Option ist.
Chris S