Каков порядок выполнения вида/компоновки MVC Razor
У меня есть бритвенный макет, например:
@using (var context = SetUpSomeContext()) {
<div>
Some content here
@RenderBody();
</div>
}
И вот такой вид:
@{
Layout = "MyLayout.cshtml";
}
<div>@SomethingThatDependsOnContextBeingSetUp()</div>
Когда представление отображается, SomethingThatDependsOnContextBeingSetUp
выполняется до SetUpSomeContext
и терпит неудачу. Это кажется странным, потому что я ожидал, что это не будет выполнено до тех пор, пока <<24 > не будет вызываться в макете. Когда я переключаю это, чтобы использовать раздел "PageContent" вместо RenderBody, все работает так, как ожидалось. Может ли кто-нибудь объяснить это поведение?
Ответы
Ответ 1
Конвейер Razor:
-
Во-первых, Razor оценивает, если присутствует, _ViewStart.cshtml, который содержит только инструкции Razor (С# или VB) для назначения макета или другой инициализации, он никогда не должен иметь html-теги внутри.
-
Затем он анализирует и оценивает файл cshtml "Просмотр" .
-
Затем он анализирует и оценивает, если присутствует, Макет, а при оценке метода @RenderBody
файла макета cshtml заменяет его на html script, полученный из оценка файла "View" cshtml.
-
Наконец, он создает html-элементы управления графами макета и просмотра html файлов.
Значит, вы не можете зависеть от каких-либо объектов "Razor" представления из операций макета, а скорее вы можете поместить в _ViewStart.cshtml вашу инициализацию объектов, видимых вашему представлению.
Вы можете представить представления cs (vb) html в виде статического содержимого, загружаемого при вызове метода Controller.View
.
В этот момент загруженный контент cshtml анализируется Razor, который оценивает выражения (назначает свойства (как макет), ветки, циклы) и строит двоичное дерево или граф объектов "HtmlControls" в ActionResult
объект, возвращаемый методом View
.
Далее, ActionResult отображается как html из Asp.Net и возвращается клиенту в качестве ответа HTTP.
Для этого Razor анализирует файлы cshtml и выполняет их код внутри частей, начиная сначала с "_ViewStart.cshtml" (также больше одного, если присутствует в цепочке подпапок, связанных с контроллером происхождения), затем следует файл cshtml загружается условными обозначениями (имя представления равно имени действия в пути Views/[имя_контроллера]/) или выраженное имя вида в качестве параметра при вызове метода View
и, наконец, конечный файл макета, связанный с представлением Layout
.
Ответ 2
Порядок выполнения от самого внутреннего до внешнего.
Я бы сказал, что использование "контекста" в том, как вы его используете, - это не лучший дизайн. Вы должны подумать о переносе установки в фильтр контроллера/действия и передать данные в представления в модели.
Ответ 3
Позвольте мне пояснить это, исследуя ситуацию. Предположим, что у вас есть вид:
@renderSection("Header")
@using (var context = SetUpSomeContext()) {
<div>
Some content here
@RenderBody();
</div>
}
@renderSection("Footer")
И мы предполагаем, что бритва выполняет страницу в ожидаемом порядке, что произойдет, если мы объявим наше мнение как?
@{
Layout = null;
}
<div>@SomethingThatDependsOnContextBeingSetUp()</div>
Razor не имеет никакого представления о том, нуждается ли это представление в макете страницы до выполнения @RenderBody(). Также будет выводиться, что она отображала страницу макета для ничего, и это было бы неразумно. это не то, что на самом деле происходит.
Когда запрос сделан, так естественно, что Razor сначала выполняет тело вашего представления.
Если ваш вид не указан, как в моей демонстрации, Razor только выводит вывод этой страницы и останавливается там. Если вид имеет макет, указанный как в вашем коде
после выполнения представления он передает элемент управления на страницу макета (страница макета начинает визуализироваться сверху вниз). Таким образом, оставшаяся страница Макет - это только размещение контента. Когда он видит @RenderBody(), он только помещает вывод уже выполненного вид.
Для разделов; они не выполняются, когда тело вашего представления выполняется после того, как ваше представление передает управление странице макета, страница макета явно вызывает выполнение ваших разделов в том порядке, в котором они объявлены.
Также обратите внимание, что вы указываете название своей страницы в своем теле просмотра, и оно отображается в теге заголовка макета (ViewBag.Title). После выполнения тела представления все переменные, объявленные в представлении тело доступно на странице макета.
Сумма: порядок рендеринга сверху вниз, но порядок выполнения отличается.
Для вашей ситуации: "SomethingThatDependsOnContextBeingSetUp выполняет перед SetUpSomeContext и не работает" . Как я уже сказал, это естественное поведение цикла выполнения Razor, просмотр тела, выполненного до выполнения страницы макета. Когда вы делаете раздел; сначала просматривается тело, но разделы не выполняются перед макетом страницы. Тело просмотра передает управление на страницу макета, а страница макета начинает визуализироваться сверху вниз, и если она видит @RenderSection, то вызывает выполнение раздела. Поэтому в этом случае выполняется SetUpSomeContext до выполнения SomethingThatDependsOnContextBeingSetUp.
Ответ 4
Если вам требуется какая-то логика во всех ваших представлениях, создайте ViewModelBase
, из которого наследуется весь ваш ViewModel
.
Затем в Controller(Base)
вы можете инициализировать ViewModel.SharedContext
и другие свойства.