Каков порядок выполнения вида/компоновки 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 и другие свойства.