HttpContextWrapper все это .... полезно? - PullRequest
26 голосов
/ 09 марта 2010

Я проходил процесс очистки кода нашего контроллера, чтобы сделать каждое действие тестируемым. Вообще говоря, это не было слишком сложно - там, где у нас есть возможность использовать фиксированный объект, такой как, например, FormsAuthentication, мы обычно вводим некоторую форму обертки в зависимости от ситуации и будем на нашем веселом пути.

По причинам, не особенно подходящим для этого разговора, когда речь шла об использовании HttpContext, мы решили использовать только что созданный класс HttpContextWrapper, а не изобретать что-то доморощенное. Одна вещь, которую мы представили, была возможность поменять местами в HttpContextWrapper (например, для модульного тестирования). Это было полностью вдохновлено тем, как Орен Эйни выполняет модульное тестирование с помощью DateTimes ( см. Статью , шаблон, который мы также используем)

public static class FooHttpContext
{
    public static Func<HttpContextWrapper> Current = () 
         => new HttpContextWrapper(HttpContext.Current);

    public static void Reset()
    {
        Current = () => new HttpContextWrapper(HttpContext.Current);
    }
}

Ничего особенного. И это прекрасно работает в нашем коде контроллера. Кикер пришел, когда мы пошли писать модульные тесты. Мы используем Moq в качестве основы для насмешек, но увы

var context = new Mock<HttpContextWrapper>() 

прерывается, так как HttpContextWrapper не имеет ctor без параметров. И что он принимает в качестве параметра ctor? Объект HttpContext. Так что я попадаю в ловушку 22.

Я использую предписанный способ для отделения HttpContext - но я не могу смоделировать значение, потому что исходный объект HttpContext был запечатан и, следовательно, его трудно проверить. Я могу сопоставить HttpContextBase, которые оба получены из - но это не дает мне того, что я хочу. Я просто что-то упускаю из-за HttpContextWrapper?

Изменить для уточнения намерения

Мы нашли способы решения проблемы - но я думаю, что главный вопрос, с которым мы уходим, - какое значение HttpContextWrapper приносит в таблицу? Я не сомневаюсь, что где-то у кого-то был а-ха! момент с ним, но он просто не приходит ко мне. Большинство публикаций, которые я вижу здесь, обсуждают это с точки зрения тестируемости - но мой собственный опыт заставил меня поверить, что это не принесло многого в этом контексте. Если мы не делаем это неправильно. (Вполне возможно).

Ответы [ 3 ]

34 голосов
/ 29 марта 2011

Этот пост в блоге объясняет это довольно хорошо:

http://splinter.com.au/httpcontext-vs-httpcontextbase-vs-httpcontext

Дело в том, что «винтажный» HttpContext не реализует HttpContextBase и не является виртуальным, и поэтому не может быть Mocked. HttpContextBase была введена в 3.5 в качестве альтернативы. Но все еще есть проблема, что винтажный HttpContext не реализует HttpContextBase.

Таким образом, HttpContextWrapper - это удобный класс-обертка (или «kludge»), который реализует HttpContextBase и может использоваться при внедрении «реального» HttpContext с использованием IOC, обычно с фабричным методом, подобным этому: () => new HttpContextWrapper(HttpContext.Current)

34 голосов
/ 09 марта 2010

Вы должны использовать реферат HttpContextBase, который намного проще издеваться, чем HttpContextWrapper.

public static Func<HttpContextBase> Current = 
    () => new HttpContextWrapper(HttpContext.Current);

А в вашем модульном тесте:

SomeClass.Current = MockHttpContextBase(); // Sorry I don't know the syntax for Moq
0 голосов
/ 23 февраля 2019

Один пример из реальной жизни, кроме тестирования. Помимо насмешек я наткнулся на особую проблему, которую класс обертки действительно помог мне решить. У нас есть приложение в Azure, и мы контролируем только приложение. Он находится за обратным прокси-сервером, который изменяет заголовок узла входящих запросов и отправляет исходный узел в настраиваемом заголовке. Приложение использует заголовок узла для создания динамических ссылок, проверки перенаправлений и т. Д., Поэтому нам нужен был способ заменить узел, заданный в свойстве HttpContext.HttpRequests.Url. Поскольку мы раскрыли HttpContext только как HttpContextBaase, используя оболочку во всем приложении, мы смогли создать класс, который наследует HttpContextWrapper и переопределяет Request, а затем возвращает объект, который наследуется от RequestWrapper и переопределяет свойство Url. Таким образом, в конце приложение заменило хост в URL, который ASP.NET использовал для контекста, на собственный хост из настраиваемого заголовка, который установил обратный прокси-сервер. В приложении не было другого способа сделать это, кроме ручного поиска кода, в котором используется HttpContext.Request.Url, и применения исправления.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...