Comment obtenir un objet HttpContext à partir de HttpContextBase dans ASP.NET MVC 1?

155

Je travaille avec des outils indépendants de WebForms / MVC, et j'ai besoin d'obtenir une instance d' HttpContextune référence donnée à un HttpContextBaseobjet. Je ne peux pas l'utiliser HttpContext.Currentcar j'ai besoin que cela fonctionne également de manière asynchrone ( HttpContext.Currentretourne nulllors d'une demande asynchrone). Je suis au courant HttpContextWrapper, mais va dans le mauvais sens.

Daniel Schaffer
la source

Réponses:

250

Le moyen le plus simple est d'obtenir l'application ApplicationInstanceet d'utiliser sa Contextpropriété:

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

(merci à Ishmael Smyrnow qui l'a noté dans les commentaires)

Réponse originale:

Vous pouvez, en particulier si l' HttpContextBaseinstance qui vous a été remise est de type HttpContextWrapperau moment de l'exécution. L'exemple suivant illustre comment procéder. Cela suppose que vous ayez une méthode appelée Fooqui accepte le contexte comme, HttpContextBasemais qui doit ensuite appeler une méthode dans un assembly tiers (que vous n'aurez peut-être pas la chance de modifier) ​​qui attend que le contexte soit tapé comme 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) { /* ... */ }

HttpContextBasea une méthode appelée GetServiceà la suite de la prise en charge IServiceProvider. Le GetServiceremplacement des HttpContextWrapperdélégués à l' GetServiceimplémentation de l' HttpContextinstance encapsulée . La GetServicemise en œuvre de HttpContextvous permet d'interroger des suspects habituels comme HttpApplication, HttpRequest, HttpResponseet ainsi de suite. Il se trouve qu'il HttpApplicationpossède une propriété appelée Context et qui renvoie une instance de HttpContext. Ainsi , on obtient à l'enveloppées par HttpContextexemple en demandant HttpContextBaseà HttpApplicationtravers GetServicepuis en lisant la Contextpropriété du revenu par HttpApplicationexemple.

Contrairement à HttpContextBase, GetServicen'apparaît pas comme un membre public de, HttpContextmais c'est parce qu'il HttpContextimplémente l' IServiceProvider.GetServiceexplicité alors que ce HttpContextBasen'est pas le cas.

Gardez à l'esprit que ce Foon'est plus testable car il repose sur la capacité de dérouler le sous-jacent HttpContextpendant les tests et qu'il est pratiquement impossible de simuler / stub en premier lieu. Le but de cette réponse, cependant, est de répondre à la question «Comment puis-je obtenir un objet HttpContext à partir de HttpContextBase?», Littéralement . La technique illustrée est utile dans les situations où vous vous retrouvez pris en sandwich entre des composants que vous n'avez pas forcément le luxe de modifier.

Atif Aziz
la source
3
Réponse très intéressante, je l'ai juste utilisée moi-même dans MVC pour passer le HttpContext d'un filtre d'erreur à ELMAH pour la journalisation.
Chris Marisic
1
belle réponse, pari qui a pris un peu de fouille :)
longhairedsi
très bonne réponse! Je l'ai utilisé en particulier dans mon contrôleur Elmah vers MVC github.com/alexanderbeletsky/elmah.mvc.controller/blob/master
Alexander Beletsky
36
Avec un HttpContextBase, ne pourriez-vous pas appeler context.ApplicationInstance.Context?
Ishmael Smyrnow
@IshmaelSmyrnow Bon sang, je ne sais pas comment j'ai raté ça parmi toutes les Http*Basevariations renvoyées par HttpContextBase. : P Je vais mettre à jour la réponse.
Atif Aziz
32

Vous pouvez,

var abstractContext = new System.Web.HttpContextWrapper(System.Web.HttpContext.Current);
Marc Chouteau
la source
16
-1 c'est la mauvaise façon, cela vous donne la base lorsque vous avez le contexte, pas l'inverse.
Chris Marisic
14

Vous ne pouvez pas.

Le but entier de HttpContextBaseest d'abstraire la dépendance à la HttpContextclasse concrète . Bien qu'il puisse contenir un élément concret HttpContext (comme c'est le cas avec httpContextWrapper) , d'autres implémentations peuvent n'avoir absolument rien à voir avec HttpContext.

Votre meilleure option est de définir une fabrique abstraite personnalisée qui peut obtenir un HttpContextBasepour vous, car vous pouvez toujours envelopper un béton HttpContextdans un fichier HttpContextWrapper.

Mark Seemann
la source
13
Cela, au fait, a été horriblement fait - je comprends que je veuille avoir une configuration pour les tests unitaires, et je comprends les couches d'abstraction - mais WTH êtes-vous censé le faire lorsque vous souhaitez utiliser des classes ASP.NET existantes qui attendent un HttpContext? (comme msdn.microsoft.com/en-us/library/… )
marq
Oui, pour tester les IHttpHandlerimplémentations, vous finissez par devoir mettre un certain nombre d'abstractions dans (wrappers de réponse) juste pour vos tests unitaires, ce qui ne semble pas correct mais finit par être la seule option.
Chris S