Как получить объект HttpContext из HttpContextBase в ASP.NET MVC 1?

155

Я работаю с некоторыми инструментами, независимыми от WebForms / MVC, и мне нужно получить экземпляр HttpContextданной ссылки на HttpContextBaseобъект. Я не могу использовать, HttpContext.Currentпотому что мне нужно, чтобы это работало также асинхронно ( HttpContext.Currentвозвращается nullво время асинхронного запроса). Я знаю HttpContextWrapper, но идет не в ту сторону.

Даниэль Шаффер
источник

Ответы:

250

Самый простой способ - получить приложение ApplicationInstanceи использовать его Contextсвойство:

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

(спасибо Измаилу Смирнову, который отметил это в комментариях)

Оригинальный ответ:

Вы можете, особенно если HttpContextBaseэкземпляр, который вам передали, имеет тип HttpContextWrapperво время выполнения. Следующий пример иллюстрирует, как вы можете это сделать. Предполагается, что у вас есть вызываемый метод, Fooкоторый принимает контекст как, HttpContextBaseно затем необходимо вызвать метод в сторонней сборке (которую вам, возможно, не удастся изменить), которая ожидает, что контекст будет напечатан как 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) { /* ... */ }

HttpContextBaseимеет метод, вызванный GetServiceв результате поддержки IServiceProvider. GetServiceПереопределение HttpContextWrapperделегатов к GetServiceреализации обернутого HttpContextэкземпляра. GetServiceРеализация HttpContextпозволяет запрашивать для обычных подозреваемых , как HttpApplication, HttpRequest, HttpResponseи так далее. Так уж получилось, что HttpApplicationимеет свойство Context и возвращает экземпляр HttpContext. Так один получает в обернутой HttpContextинстанции с просьбой HttpContextBaseза HttpApplicationпомощью с GetServiceпоследующим чтением Contextсвойства возвращаемого HttpApplicationэкземпляра.

В отличие от этого HttpContextBase, GetServiceне отображается как открытый член, HttpContextно это потому, что HttpContextреализует IServiceProvider.GetServiceпростоту, а HttpContextBaseне делает.

Имейте в виду, что Fooон больше не подлежит HttpContextтестированию, поскольку полагается на возможность развернуть базовый элемент во время тестирования и, во-первых, практически невозможно подделать / заглушить. Суть этого ответа, однако, заключается в том, чтобы ответить на вопрос «Как получить объект HttpContext из HttpContextBase?», Буквально . Проиллюстрированная техника полезна в тех ситуациях, когда вы оказались зажаты между компонентами, которые не обязательно можете изменить.

Атиф Азиз
источник
3
Очень интересный ответ, я сам использовал его в MVC, чтобы передать HttpContext из фильтра ошибок в ELMAH для ведения журнала.
Крис Марисик
1
хороший ответ, поспорим, что это заняло немного копания? :)
longhairedsi
отличный ответ! Я использовал это, особенно в моем контроллере Elmah
Александр Белецкий
36
С HttpContextBase не могли бы вы позвонить context.ApplicationInstance.Context?
Измаил Смирнов
@IshmaelSmyrnow Черт возьми, не то, как я пропустил это среди всех Http*Baseвариантов, возвращенных HttpContextBase. : P Я обновлю ответ.
Атиф Азиз
32

Ты можешь,

var abstractContext = new System.Web.HttpContextWrapper(System.Web.HttpContext.Current);
Марк Шуто
источник
16
-1 это неправильный путь, это дает вам базу, когда у вас есть контекст, а не наоборот.
Крис Марисик
14

Ты не можешь

Вся цель HttpContextBaseсостоит в том, чтобы абстрагироваться от зависимости от конкретного HttpContextкласса. Хотя он может содержать конкретный HttpContext (как в случае с httpContextWrapper) , другие реализации могут не иметь абсолютно никакого отношения к HttpContext.

Лучший вариант - определить собственную абстрактную фабрику, которая может получить HttpContextBaseдля вас, поскольку вы всегда можете обернуть бетон HttpContextв HttpContextWrapper.

Марк Симанн
источник
13
Между прочим, это было ужасно сделано - я понимаю, что хочу иметь настройку для модульных тестов, и я понимаю слои абстракции - но WTH вы должны делать, когда вы хотите использовать существующие классы ASP.NET, которые ожидают HttpContext? (как msdn.microsoft.com/en-us/library/... )
MARQ
Да, чтобы протестировать IHttpHandlerреализации, вы заканчиваете тем, что вынуждены помещать в абстракции (обертки Response) определенное количество абстракций только для своих модульных тестов, что не кажется правильным, но в конечном итоге является единственным вариантом.
Крис С