C# MVC Razor视图/布局的执行顺序是什么

C# MVC Razor视图/布局的执行顺序是什么,c#,asp.net-mvc-3,razor,C#,Asp.net Mvc 3,Razor,我的剃须刀布局如下: @using (var context = SetUpSomeContext()) { <div> Some content here @RenderBody(); </div> } 使用(var context=SetUpSomeContext()){ 这里有一些内容 @RenderBody(); } 和一个类似于: @{ Layout = "MyLayout.cshtml"; } <

我的剃须刀布局如下:

@using (var context = SetUpSomeContext()) {
    <div>
        Some content here
        @RenderBody();
    </div>
}
使用(var context=SetUpSomeContext()){ 这里有一些内容 @RenderBody(); } 和一个类似于:

@{
    Layout = "MyLayout.cshtml";
}
<div>@SomethingThatDependsOnContextBeingSetUp()</div>
@{
Layout=“MyLayout.cshtml”;
}
@依赖于上下文设置()的某些内容

当视图呈现时,
SetUpSomeContext
SetUpSomeContext
之前执行
somethingatdependsoncontextbeingsetup
并失败。这看起来很奇怪,因为我希望在布局中调用
RenderBody
之前不会执行。当我将其切换为使用“PageContent”部分而不是RenderBody时,一切正常。有人能解释这种行为吗?

执行顺序是从最里面到最外面


我认为使用“上下文”的方式不是最好的设计——你应该考虑将安装程序移到控制器/动作过滤器上,并将数据传递给模型中的视图。

< P>如果你需要在所有视图上都有逻辑,创建一个<代码> ViewModelBase <代码>,所有的<代码> VIEWSMOD> <代码>继承。p>
然后在您的
控制器(基本)
中,您可以初始化
视图模型.SharedContext
和其他属性。

让我通过调查一种情况来澄清这一点,假设您具有类似视图的属性

 @renderSection("Header")
    @using (var context = SetUpSomeContext()) {
        <div>
            Some content here
            @RenderBody();
        </div>
    }
   @renderSection("Footer")
@renderSection(“标题”)
@使用(var context=SetUpSomeContext()){
这里有一些内容
@RenderBody();
}
@渲染部分(“页脚”)
我们假设razor按照您期望的顺序执行页面,如果我们像这样声明视图,会发生什么

@{
    Layout = null;
}
<div>@SomethingThatDependsOnContextBeingSetUp()</div>
@{
布局=空;
}
@依赖于上下文设置()的某些内容
Razor在执行@RenderBody()之前根本不知道该视图是否需要布局页面。而且它会推断该视图渲染布局页面是徒劳的,这是不合理的。因此,实际情况并非如此

当提出请求时,Razor首先执行视图主体是很自然的。 如果您的视图没有像“我的演示剃须刀”中那样指定布局,则只呈现该页面的输出并停止在那个里 执行视图后,它将控制权传递给布局页面(布局页面开始从上到下呈现),因此布局页面剩下的只是内容放置。当它看到@RenderBody()时,它只放置已执行视图的输出

适用于章节;当视图主体执行时,它们不会执行。在视图将控制权传递给布局页面后,布局页面将按照声明的顺序显式调用节的执行

还请注意,您正在视图正文中指定页面标题,并且它将呈现在布局标题标记(ViewBag.title)中。执行视图正文后,视图正文中声明的所有变量将在布局页面中可用

总和:呈现顺序是从上到下,但执行顺序不同


针对您的情况在SetUpSomeContext之前执行SetUpSomeContext并失败的somethingatdependsoncontextbeingsetup“。就像我说的,这是剃须刀执行周期的自然行为,在执行布局页面之前查看执行的主体;首先执行视图正文,但在布局页之前不执行节。视图正文将控制权传递给布局页,布局页开始从上到下呈现,如果它看到@RenderSection,则调用节的执行。因此,在这种情况下,SetUpSomeContext在someThingAtDependsOnContextBeingSetup之前执行已执行。

剃须刀管道是:

  • 首先,Razor评估(如果存在)\u ViewStart.cshtml仅包含Razor语句(C#或VB)用于分配布局或其他初始化,它内部不应该有html标记

  • 然后,它解析并计算“查看”cshtml文件

  • 然后,它解析并计算(如果存在)布局,当计算cshtml布局文件的
    @RenderBody
    方法时,将其替换为计算“查看”cshtml文件产生的html脚本

  • 最后,构建了布局和查看html文件的html控制图对象


  • 因此您不能从布局操作中依赖视图的任何“剃刀”对象,而是可以将视图可见对象的初始化放入_ViewStart.cshtml中


    当调用
    Controller.View
    方法时,您可能会将cs(vb)html视图想象为加载的静态内容

    此时,cshtml加载的内容由Razor解析,Razor计算表达式(分配属性(如布局)、分支、循环),并在
    View
    方法返回的
    ActionResult
    对象中构建一种“HTMLControl”对象的二叉树或图形

    接下来,ActionResult从Asp.Net呈现为html,并作为http响应返回给客户端


    为此,Razor解析cshtml文件并在部分内部执行其代码,首先从“_ViewStart.cshtml”(如果与源控制器相关的子文件夹链中存在多个cshtml),然后按照约定加载cshtml文件(视图名称等于路径视图中的操作名称/[ControllerName]/),或者在调用
    view
    方法时,通过表达式视图的名称作为参数,最后是通过
    layout
    属性链接到视图的最终布局文件

    但是分区不遵循这个规则?另外,我使用这种方法的原因是,我希望启用一些常见的渲染功能,而不需要每个控制器方法都更改其调用View()的方式。我不希望在所有视图中都使用这种逻辑,只希望在整个页面中使用这种逻辑。您是否仍然建议在布局上使用ViewModelBase