HttpContext.Items с ASP.NET MVC

Я использую свой собственный класс ApplicationContext, который использует шаблон синглтона. Я хочу сохранить свой экземпляр в HttpContext.Items, так как он доступен во всех частях запроса. Я читал об использовании HttpContext с ASP.NET MVC, и одна из основных проблем заключается в том, что он вводит сложность тестирования. Я пытался исследовать тестируемость HttpContext.Items, но все, что я могу найти, - это материал на Session. Единственное, что я нашел, - это пример главы в книге Professional ASP.NET 3.5 MVC по Wrox ( ссылка в формате PDF здесь). На странице 15 говорится следующее:

Что-то, что вы не можете использовать: HttpContext.Items
Выше в этом разделе мы пришли к выводу, что солгали вам: HttpContext не является общим для ASP.NET MVC и ASP.NET Web Forms. В результате этого вы не можете использовать коллекцию HttpContext.Items для хранения и извлечения битов данных.

Причина этого заключается в том, что после перенаправления на контроллер ваш HttpHandler становится System.Web.Mvc.MvcHandler, который создается с помощью HttpContextWrapper, который будет иметь собственное определение HttpContext.Current. К сожалению, во время этого рукопожатия такие вещи, как HttpContext.Items не передаются.

Это сводится к тому, что типы HttpContext, несмотря на то, что они выглядят и звучат практически одинаково, не одинаковы, и вы не можете передавать данные таким образом.

Теперь я попытался проверить это, и, насколько я могу судить, если вы перенаправляете на другой контроллер с помощью RedirectToAction, HttpContext.Items остается. Я использую проект ASP.NET MVC по умолчанию, чтобы проверить это. Что я сделал, добавьте этот метод в Global.asax.cs:

protected void Application_BeginRequest()
{
    Context.Items["Test"] = "Hello World";
}

А в HomeController.cs я изменил метод Index на:

public ActionResult Index()
{
    return RedirectToAction("About");
}

И изменил метод О:

public ActionResult About()
{
    Response.Write(Convert.ToString(HttpContext.Items["Test"]));
    return View();
}

Когда я запускаю приложение, страница правильно перенаправляется в /Home/About и Response.Написывает правильную строку "Hello World", установленную в global.asax.cs.

Таким образом, мне кажется, что я либо не понимаю, что означает книга, когда они говорят "такие вещи, как HttpContext.Items не передаются" ИЛИ он действительно передает эти вещи, и можно использовать HttpContext.Items.

Если вы, ребята, порекомендуете мне избегать HttpContext.Items, есть ли другой альтернативный способ хранения объекта в запросе для каждого запроса?

3 ответа

Решение

Ваш вопрос задает несколько вещей, но я думаю, что пункт № 1 - это ответ, который вы ищете.

  1. Это нормально использовать Context.Items для кэширования на основе запроса? Да. Если в процессе, по запросу, для каждой машины в веб-ферме вы используете критерии, Context.Items дает вам это.

  2. Является Context.Items сложно проверить? Что касается тестируемости, я бы скрыл Context.Items за интерфейс какой-то. Таким образом, вы получаете возможности модульного тестирования без ссылки Context.Items непосредственно. В противном случае, что вы должны проверить Context.Items? Что фреймворк будет хранить и извлекать значения? Держите ваш код в неведении System.Web и ты будешь счастливым туристом.

  3. Будет Context.Items уцелеть RedirectToAction? Ваш тест недействителен. Он устанавливает "Привет, мир" для каждого веб-запроса, и ваш тест охватывает два веб-запроса. Первый - когда вызывается действие Index. Второй, когда RedirectToAction действие называется (это HTTP 302). Чтобы это не сработало, установите новое значение в действии "Индекс" и посмотрите, сохраняется ли оно в действии "О программе".

Используйте словарь TempData, он в основном предназначен для хранения объектов между перенаправлениями действий:

public ActionResult Index()
{
    TempData.Add("Test", "Hello world");
    return RedirectToAction("About");
}

public ActionResult About()
{
    ViewData["Test"] = TempData["Test"];
    return View();
}

Затем получите значение в вашем представлении:

<%=ViewData["Test"] %>

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

Другие вопросы по тегам