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

时间:2013-08-13 13:33:56

标签: c# asp.net-mvc-3 razor

我有一个剃刀布局,如:

@using (var context = SetUpSomeContext()) {
    <div>
        Some content here
        @RenderBody();
    </div>
}

这样的观点:

@{
    Layout = "MyLayout.cshtml";
}
<div>@SomethingThatDependsOnContextBeingSetUp()</div>

当视图呈现时,SomethingThatDependsOnContextBeingSetUpSetUpSomeContext之前执行并失败。这看起来很奇怪,因为我希望在布局中调用RenderBody之前不要执行。当我将其切换为使用“PageContent”部分而不是RenderBody时,一切都按预期工作。任何人都可以解释这种行为吗?

4 个答案:

答案 0 :(得分:13)

Razor管道是:

  1. 首先,Razor评估(如果存在)仅包含用于分配布局或其他初始化的Razor语句(C#或VB)的 _ViewStart.cshtml ,它应该永远不会有html标签。

  2. 然后,它解析并评估&#34; View&#34; cshtml文件

  3. 然后,它解析并评估(如果存在)布局,并在评估cshtml布局文件的@RenderBody方法时,将其替换为由评估&#34;查看&#34; cshtml文件。

  4. 最后,它构建了布局和查看html文件的html控件图形对象。


  5. 所以,你不能依赖任何&#34; Razor&#34;布局操作视图的对象,而不是您可以在_ViewStart.cshtml中放置视图可见对象的初始化


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

    此时,加载cshtml的内容由Razor解析,用于评估表达式(分配属性(如布局),分支,循环)并构建一种二进制树或图形&#34; HtmlControls&#34;将对象放入ActionResult方法返回的View对象中。

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

    要做到这一点,Razor会解析cshtml文件,并在第一部分从#34; _ViewStart.cshtml&#34;开始执行代码。 (还有一个如果存在于与原始控制器相关的子文件夹链中),则遵循由约定加载的cshtml文件(视图名称等于路径Views / [ControllerName] /中的操作名称),或者通过表达调用View方法时视图的名称作为参数,最后,Layout属性链接到视图的最终布局文件。

答案 1 :(得分:6)

让我通过调查一个情况来澄清这一点,假设你有这样的观点;

 @renderSection("Header")
    @using (var context = SetUpSomeContext()) {
        <div>
            Some content here
            @RenderBody();
        </div>
    }
   @renderSection("Footer")

我们假设razor按照您期望的顺序执行页面,如果我们声明我们的视图会发生什么?

@{
    Layout = null;
}
<div>@SomethingThatDependsOnContextBeingSetUp()</div>

在执行 @RenderBody()之前,Razor不知道该视图是否需要布局页面。同时它会推断出它没有渲染布局页面,这也不合理。所以这个事实并非如此。

当请求变得如此自然以至于Razor首先执行你的视图体。 如果您的视图没有像我的演示中那样指定布局Razor只渲染该页面的输出并停在那里。如果视图具有像您的代码中指定的布局 在执行视图后,它将控件传递给布局页面。(布局页面开始从上到下渲染)那么布局页面的剩余部分只是内容放置。当它看到@RenderBody()时,它只放置已执行的输出图。

对于部分;当你的视图将控件传递给布局页面时,它们不会在你的视图体执行时执行,布局页面会按照它们被声明的顺序显式地调用你的部分的执行。

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

总和:渲染顺序是从上到下,但执行顺序不同。

适合您的情况&#34; SomethingThatDependsOnContextBeingSetUp在SetUpSomeContext之前执行并失败&#34; 。就像我说的那样是Razor执行周期的自然行为,在执行布局页面之前执行了查看主体。当你创建它时;视图主体首先执行但部分不在布局页面之前执行。视图主体将控件传递给布局页面,布局页面从上到下开始渲染,如果看到@RenderSection则调用section的执行。在这种情况下,执行SetUpSomeContext在SomethingThatDependsOnContextBeingSetUp执行之前。

答案 2 :(得分:4)

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

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

答案 3 :(得分:0)

如果您需要在所有观看中使用某种逻辑,请创建ViewModelBase以继承所有ViewModel个。

然后在您的Controller(Base)中,您可以初始化ViewModel.SharedContext和其他属性。