我有一个剃刀布局,如:
@using (var context = SetUpSomeContext()) {
<div>
Some content here
@RenderBody();
</div>
}
这样的观点:
@{
Layout = "MyLayout.cshtml";
}
<div>@SomethingThatDependsOnContextBeingSetUp()</div>
当视图呈现时,SomethingThatDependsOnContextBeingSetUp
在SetUpSomeContext
之前执行并失败。这看起来很奇怪,因为我希望在布局中调用RenderBody
之前不要执行。当我将其切换为使用“PageContent”部分而不是RenderBody时,一切都按预期工作。任何人都可以解释这种行为吗?
答案 0 :(得分:13)
Razor管道是:
首先,Razor评估(如果存在)仅包含用于分配布局或其他初始化的Razor语句(C#或VB)的 _ViewStart.cshtml ,它应该永远不会有html标签。
然后,它解析并评估&#34; View&#34; cshtml文件。
然后,它解析并评估(如果存在)布局,并在评估cshtml布局文件的@RenderBody
方法时,将其替换为由评估&#34;查看&#34; cshtml文件。
最后,它构建了布局和查看html文件的html控件图形对象。
所以,你不能依赖任何&#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
和其他属性。