Как ViewBag в ASP.NET MVC работает за кулисами?
Я читаю книгу по ASP.NET MVC, и мне интересно, как работает следующий пример:
Пример # 1
контроллер
public class MyController : Controller
{
public ActionResult Index()
{
ViewBag.MyProperty = 5;
return View();
}
}
Вид
<h1>@ViewBag.MyProperty</h1>
Теперь я понимаю, что ViewBag
- это динамический объект, так что как вы можете установить свойство (хотя я мало знаю о динамических объектах, никогда не работал с ними.) Но как представление получает конкретный экземпляр от ViewBag
от контроллера, хотя мы ничего не передаем напрямую?
Я думал, что ViewBag
может быть объектом public
static
, но тогда любое его изменение было бы глобальным и не было бы специфичным для экземпляра представления.
Не могли бы вы рассказать о том, как это работает за кулисами?
Пример # 2
контроллер
public class MyController : Controller
{
public ActionResult Index()
{
ViewBag.MyProperty = 5;
return View();
}
public ActionResult Index2()
{
ViewBag.MyProperty = 6;
return View();
}
}
Теперь скажем, сначала вызывается метод Index
, а затем Index2
. В конце значение ViewBag.MyProperty
закончится как 6 (значение от Index2
). Я чувствую, что это нехорошо делать, но в то же время я чувствую, что я думаю о настольных разработках. Может быть, это не имеет значения, когда используется с ASP.NET MVC, так как сеть не имеет апатридов. Это тот случай?
Ответы
Ответ 1
ViewBag
является свойством ControllerBase
, от которого должны наследоваться все контроллеры. Это объект dynamic
, поэтому вы можете добавлять к нему новые свойства, не получая ошибок времени компиляции.
Это не static
, это элемент объекта. Во время существования запроса экземпляр контроллера создается и удаляется, поэтому у вас не будет проблем с "concurrency", например, для перезаписи значения.
Метод View
(и его варианты) также не является static
, и это то, как представление получает значения ViewBag
: во время процесса визуализации экземпляр контроллера имеет свой экземпляр ViewBag как хорошо.
Ответ 2
Если вы проанализировали класс ControllerBase, вы увидите, что свойство ViewBag является "прокси" для свойства ViewData, чтобы сделать ваш исходный вид лучше. (Я даже помню, как Скотт Гензельман взял интервью у Фила Хаака, где Фил представил свойство ViewBag как ярлык для ViewData и избавил от необходимости повторных квадратных скобок и цитат). Хотя свойство ViewBag
отображается как объект dynamic
, оно реализует класс DynamicViewDataDictionary, который работает непосредственно с ViewData.
Рассматривая исходный код класса Controller, вы можете найти этот метод:
protected internal virtual ViewResult View(string viewName, string masterName, object model)
Итак, в основном, когда вы вызываете return View();
с вашего контроллера, он создает новый экземпляр класса ActionResult
, передающий ViewData из контроллера в конструктор. Экземпляр ActionResult
затем передается в определенный механизм просмотра (ASPX, Razor), поэтому его можно использовать для визуализации рассматриваемого представления.
Создание ViewBag/ViewData public static может быть вредным. Каждый веб-запрос в ваше приложение MVC создает новый экземпляр контроллера. Если у вас будет ViewData/ViewBag как public static, то два одновременных пользователя будут делиться одними и теми же данными из ViewBag/ViewData.
Здесь - это видео. Обсуждение в ViewBag (formder ViewModel) начинается в 04:05
Ответ 3
ViewBag
является свойством ControllerBase
. Он определяется следующим образом:
public Object ViewBag { get; }
Обратите внимание, что эта подпись фактически неверна. Вот как выглядит исходный код:
public dynamic ViewBag {
get {
if (_dynamicViewDataDictionary == null) {
_dynamicViewDataDictionary = new DynamicViewDataDictionary(() => ViewData);
}
return _dynamicViewDataDictionary;
}
}
_dynamicViewDataDictionary
- это ExpandoObject; вы можете добавлять к нему свойства во время выполнения. Его срок службы такой же, как у контроллера, который является временем жизни HTTP-запроса.