Jak uzyskać obiekt HttpContext z HttpContextBase w ASP.NET MVC 1?

154

Pracuję z niektórymi narzędziami WebForms / MVC-agnostic i muszę uzyskać wystąpienie HttpContextdanego odniesienia do HttpContextBaseobiektu. Nie mogę użyć, HttpContext.Currentponieważ potrzebuję, aby to również działało asynchronicznie ( HttpContext.Currentzwracane nullpodczas żądania asynchronicznego). Jestem tego świadomy HttpContextWrapper, ale idzie w złą stronę.

Daniel Schaffer
źródło

Odpowiedzi:

249

Najprostszym sposobem jest pobranie aplikacji ApplicationInstancei wykorzystanie jej Contextwłaściwości:

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

(podziękowania dla Ishmaela Smyrnow, który zauważył to w komentarzach)

Oryginalna odpowiedź:

Możesz, zwłaszcza jeśli przekazana HttpContextBaseinstancja jest typu HttpContextWrapperw czasie wykonywania. Poniższy przykład ilustruje, jak możesz to zrobić. Zakłada się, że masz metodę o nazwie, Fooktóra akceptuje kontekst jako, HttpContextBaseale następnie musi wywołać metodę w zestawie innej firmy (której możesz nie mieć szczęścia do zmodyfikowania), która oczekuje, że kontekst zostanie wpisany jako 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) { /* ... */ }

HttpContextBasema metodę wywołaną GetServicew wyniku wsparcia IServiceProvider. GetServiceOminięcie HttpContextWrapperdelegatów do GetServicerealizacji zawiniętego HttpContextinstancji. GetServiceImplementacja HttpContextpozwala na zapytania dla Podejrzani jak HttpApplication, HttpRequest, HttpResponsei tak dalej. Tak się składa, że HttpApplicationma właściwość o nazwie Context, która zwraca instancję HttpContext. Tak więc można dostać się do opakowanej HttpContextinstancji, prosząc HttpContextBaseo HttpApplicationvia, GetServicea następnie odczytując Contextwłaściwość zwróconej HttpApplicationinstancji.

W przeciwieństwie do HttpContextBase, GetServicenie pojawia się jako publiczny członek, HttpContextale to dlatego, że HttpContextimplementuje IServiceProvider.GetServicejawność, a HttpContextBasenie.

Należy pamiętać, że Foonie jest to już możliwe do przetestowania, ponieważ polega na możliwości rozpakowania elementu bazowego HttpContextpodczas testowania i jest prawie niemożliwe do sfałszowania / zablokowania w pierwszej kolejności. Jednak celem tej odpowiedzi jest dosłownie odpowiedź na pytanie „Jak uzyskać obiekt HttpContext z HttpContextBase?” . Zilustrowana technika jest przydatna w sytuacjach, w których znajdujesz się wciśnięty między komponenty, których modyfikacja niekoniecznie jest luksusowa.

Atif Aziz
źródło
3
Bardzo interesująca odpowiedź, po prostu użyłem jej w MVC do przekazania HttpContext z filtru błędów do ELMAH w celu zalogowania.
Chris Marisic
1
ładna odpowiedź, założę się, że trzeba było trochę kopać? :)
longhairedsi
świetna odpowiedź! Wykorzystałem to szczególnie w moim kontrolerze Elmah do MVC github.com/alexanderbeletsky/elmah.mvc.controller/blob/master/…
Alexander Beletsky
35
Nie możesz zadzwonić z HttpContextBase context.ApplicationInstance.Context?
Ishmael Smyrnow,
@IshmaelSmyrnow Cholera, nie jak przegapiłem to wśród wszystkich Http*Basezwróconych przez nas odmian HttpContextBase. : P Zaktualizuję odpowiedź.
Atif Aziz
32

Możesz,

var abstractContext = new System.Web.HttpContextWrapper(System.Web.HttpContext.Current);
Marc Chouteau
źródło
16
-1 to jest zły sposób, to daje podstawę, gdy masz kontekst, a nie na odwrót.
Chris Marisic
14

Nie możesz.

Celem programu HttpContextBasejest oderwanie od zależności od konkretnej HttpContextklasy. Chociaż może zawierać konkret HttpContext (tak jak w przypadku httpContextWrapper) , inne implementacje mogą nie mieć absolutnie nic wspólnego HttpContext.

Najlepszą opcją jest zdefiniowanie niestandardowej fabryki abstrakcyjnej, która może uzyskać HttpContextBasedla Ciebie, ponieważ zawsze możesz owinąć beton HttpContextw plik HttpContextWrapper.

Mark Seemann
źródło
12
Nawiasem mówiąc, zostało to okropnie zrobione - rozumiem, że chcesz mieć konfigurację do testów jednostkowych i rozumiem warstwy abstrakcji - ale WTH masz zrobić, gdy chcesz użyć istniejących klas ASP.NET, które oczekują HttpContext? (jak msdn.microsoft.com/en-us/library/… )
marq
Tak, aby przetestować IHttpHandlerimplementacje, kończysz z koniecznością umieszczenia dodatkowej liczby abstrakcji w (opakowaniach odpowiedzi) tylko dla testów jednostkowych, co nie wydaje się właściwe, ale w końcu jest jedyną opcją.
Chris S,