I have a razor layout like:
@using (var context = SetUpSomeContext()) {
<div>
Some content here
@RenderBody();
</div>
}
And a view like:
@{
Layout = "MyLayout.cshtml";
}
<div>@SomethingThatDependsOnContextBeingSetUp()</div>
When the view renders, SomethingThatDependsOnContextBeingSetUp
executes before SetUpSomeContext
and fails. This seems weird, because I would expect that not to execute until RenderBody
is called in the layout. When I switch this to use a "PageContent" section instead of RenderBody, everything works as expected. Can anyone explain this behavior?
Razor is a markup syntax that lets you embed server-based code into web pages using C# and VB.Net. It is not a programming language. It is a server side markup language. Razor has no ties to ASP.NET MVC because Razor is a general-purpose templating engine. You can use it anywhere to generate output like HTML.
Razor is a simple programming syntax for embedding server code in web pages. Razor syntax is based on the ASP.NET framework, the part of the Microsoft.NET Framework that's specifically designed for creating web applications.
The layout view allows you to define a common site template, which can be inherited in multiple views to provide a consistent look and feel in multiple pages of an application. The layout view eliminates duplicate coding and enhances development speed and easy maintenance.
The Razor pipeline is:
First, Razor evaluates, if present, _ViewStart.cshtml that contains only Razor statements (C# or VB) for assign Layout or other initialization, it should never have html tags inside.
Then, it parse and evaluates the "View" cshtml file.
Then, it parse and evaluates, if present, the Layout, and when evaluates the @RenderBody
method of the cshtml layout file, replaces it with the html script resulting from evaluation of "View" cshtml file.
Finally, it builds the html control graph objects of layout and view html files.
So, you cannot do depend any "Razor" objects of a view from layout operations, but rather you may put in _ViewStart.cshtml your initialization of objects visible to your view.
You may imagine cs(vb)html views as a static content loaded when Controller.View
method is called.
At that point, the cshtml loaded content is parsed by Razor that evaluates the expressions (assign properties(as Layout), branchs, loops) and build a sort of binary tree or graph of "HtmlControls" objects into the ActionResult
object returned by View
method.
Next, ActionResult is rendered as html from Asp.Net and returned to the client as http response.
To do that, Razor parses cshtml files and carries out their code inside parts starting first from the "_ViewStart.cshtml" (also more of one if present in the sub folders chain related to the origin controller), then follows cshtml file loaded by conventions (name of view equals to the name of action in the path Views/[ControllerName]/), or by expressed view's name as parameter when calling View
method, and finally, the eventual layout file linked to the view by Layout
property.
Let me clarify this by investigating a situation,Assume that you have view like;
@renderSection("Header")
@using (var context = SetUpSomeContext()) {
<div>
Some content here
@RenderBody();
</div>
}
@renderSection("Footer")
And we are assuming that razor executes the page in the order you expect, what would happen if we declared our view like?
@{
Layout = null;
}
<div>@SomethingThatDependsOnContextBeingSetUp()</div>
Razor would not have any idea whether that view needs a layout page until executing @RenderBody().Also it would deduce that it rendered layout page for nothing and this would not be reasonable.So this is not what actually happens.
When request made it is so natural that Razor first executes body of your view. If your view not specified layout like in my demo Razor only renders output of that page and stops there.If view has a layout specified like in your code after executing the view , it passes control to layout page.(Layout page starts to render from top to bottom)So what is remaining for Layout page is only content placement.When it sees @RenderBody() it only places output of your already executed view.
For sections; they are not executed when your view body executed, after your view passes control to layout page,layout page explicitly invokes the execution of your sections in the order they are declared.
Also notice that you are specifying your page title in your view body and it is rendered in your layout title tag (ViewBag.Title).After executing view body all the variables which is declared in view body are available in layout page.
Sum:Rendering order is from top to bottom but execution order is different.
For your situation: "SomethingThatDependsOnContextBeingSetUp executes before SetUpSomeContext and fails". Like i said it is natural behaviour of Razor execution cycle, view body executed before layout page executed.When you make it section ; view body executed first but sections are not executed before layout page.View body passes control to layout page and Layout page starts to render from top to bottom and if it sees @RenderSection then invokes the execution of section.So in this case SetUpSomeContext is executed before SomethingThatDependsOnContextBeingSetUp executed.
The execution order is from innermost to outermost.
I would argue that using a 'context' the way you use it is not the best design - you should consider moving the setup to the controller / action filter and pass the data to the views in model.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With