Como obtenho um objeto HttpContext do HttpContextBase no ASP.NET MVC 1?

155

Estou trabalhando com algumas ferramentas independentes de WebForms / MVC e preciso obter uma instância de HttpContextuma referência a um HttpContextBaseobjeto. Não posso usá-lo HttpContext.Currentporque também preciso que isso funcione de forma assíncrona ( HttpContext.Currentretorna nulldurante uma solicitação assíncrona). Estou ciente HttpContextWrapper, mas segue o caminho errado.

Daniel Schaffer
fonte

Respostas:

250

A maneira mais simples é obter o aplicativo ApplicationInstancee usar sua Contextpropriedade:

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

(obrigado a Ishmael Smyrnow, que observou isso nos comentários)

Resposta original:

Você pode, especialmente se a HttpContextBaseinstância que você recebeu é do tipo HttpContextWrapperem tempo de execução. O exemplo a seguir ilustra como você pode fazer isso. Supõe que você tenha um método chamado Fooque aceita o contexto, HttpContextBasemas que precisa chamar um método em um assembly de terceiros (que talvez você não tenha a sorte de modificar) que espera que o contexto seja digitado 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) { /* ... */ }

HttpContextBasetem um método chamado GetServicecomo resultado do suporte IServiceProvider. A GetServicesubstituição de HttpContextWrapperdelegados para a GetServiceimplementação da HttpContextinstância agrupada . A GetServiceimplementação do HttpContextpermite que você consulta para os suspeitos habituais, como HttpApplication, HttpRequest, HttpResponsee assim por diante. Acontece que HttpApplicationtem uma propriedade chamada Context e que retorna uma instância de HttpContext. Assim se obtém na envolto HttpContextexemplo, pedindo HttpContextBasepara HttpApplicationvia GetServiceseguido pela leitura da Contextpropriedade do retornado HttpApplicationinstância.

Ao contrário HttpContextBase, GetServicenão aparece como um membro público de, HttpContextmas isso ocorre porque HttpContextimplementa IServiceProvider.GetServiceexplicitamente enquanto HttpContextBasenão.

Lembre-se de que Foonão é mais testável porque depende de ser capaz de desembrulhar o subjacente HttpContextdurante o teste e que é quase impossível de falsificar / stub em primeiro lugar. O objetivo desta resposta, no entanto, é abordar a pergunta "Como obtenho um objeto HttpContext do HttpContextBase?", Literalmente . A técnica ilustrada é útil nas situações em que você se encontra imprensado entre componentes que não tem necessariamente o luxo de modificar.

Atif Aziz
fonte
3
Resposta muito interessante, usei-me no MVC para passar o HttpContext de um filtro de erro para o ELMAH para log.
Chris Marisic 2/02
1
boa resposta, apostou que demorou um pouco para cavar? :)
longhairedsi
Ótima resposta! I utilizado que, especialmente no meu Elmah para MVC controlador github.com/alexanderbeletsky/elmah.mvc.controller/blob/master/...
Alexander Beletsky
36
Com um HttpContextBase, você não poderia ligar context.ApplicationInstance.Context?
Ishmael Smyrnow 5/10
@IshmaelSmyrnow Porra, não como eu perdi isso entre todas as Http*Basevariações retornadas por HttpContextBase. : P vou atualizar a resposta.
Atif Aziz 12/12
32

Você pode,

var abstractContext = new System.Web.HttpContextWrapper(System.Web.HttpContext.Current);
Marc Chouteau
fonte
16
-1 esse é o caminho errado, isso fornece a Base quando você tem o Contexto, e não o contrário.
Chris Marisic
14

Você não pode.

O objetivo de todo HttpContextBaseé abstrair a dependência da HttpContextclasse concreta . Embora possa conter um concreto HttpContext (como é o caso httpContextWrapper) , outras implementações podem não ter absolutamente nada a ver HttpContext.

Sua melhor opção é definir um Abstract Factory personalizado que possa ser útil HttpContextBasepara você, pois você sempre pode envolver um concreto HttpContextem um HttpContextWrapper.

Mark Seemann
fonte
13
A propósito, isso foi horrivelmente feito - eu entendo querer ter uma configuração para testes de unidade e camadas de abstração - mas o que você deve fazer quando deseja usar as classes existentes do ASP.NET que esperam um HttpContext? (como msdn.microsoft.com/en-us/library/… )
marq
Sim, para testar IHttpHandlerimplementações, você precisa inserir um número ainda pequeno de abstrações (wrappers de resposta) apenas para seus testes de unidade, o que não parece certo, mas acaba sendo a única opção.
Chris S