Thursday 16 December 2010

Dive deep into ASP.NET MVC Razor view rendering process

Introduction
These few days I spent some time studied the inner rendering process of the new Razor view engine for ASP.NET MVC 3. I would like to share my finds with you here.

Background
ASP.NET MVC executing starts with MvcHandler.ProcessRequest() and it follows the following path if the controller is returning a ViewResult,

RazorView.RenderView() View rendering starts from ViewEngine specific view's RenderView() method. For Razor ViewEngine, that is RazorView's RenderView(). The following is the code.

It first casts the instance object to WebViewPage. The instance object is an instance of class compiled from our view code. Then it sets some properties, looks for StartPage (if it is a normal view, the RunViewStartPages is true, if it is a partial view, RunViewStartPages is false) and calls webViewPage.ExecutePageHierarchy(). ExecutePageHierarchy is defined in System.Web.WebPages.WebPageBase class and is not overridden by any sub classes. And there are two versions, one is virtual and without any parameter, while the other one is non-virtual and with a bunch of parameters.

Non Virtual WebPageBase.ExecutePageHierarchy()
RenderView() is calling the non-virtual one. The following is the code,


It first calls PushContext to save current context information, then checks whether there is a start page (defined by _ViewStart.cshtml file). If yes, then calls start page's ExecutePageHierarchy(), otherwise calls the ExecutePageHierarchy() virtual function. And finally calls PopContext() to clean up.

PushContext() and Preparation for Rendering


  1. It firstly saves parameter "writer" to _currentWriter and also the context information. The parameter "writer" is HttpContext.Response.Output object from ViewResultBase.ExecuteResult()
  2. It then creates a TextWriter (_tempWriter) object and pushes it to the OutputStack.
  3. It then pushes a new Dictionary object to SectionWritersStack
  4. It then assigns the BodyAction to _body variable if it is not null

We need to pay particular attention to the step 2 & 3. OutputStack is defined in PageContext, it is a stack of TextWriter


If you check Write() and WriteLiteral() methods defined in WebPageBase, you will notice that they all write to Output object which is the top object from OutputStack. So the purpose of the step2 is to write all contents to _tempWriter, not to the "writer" parameter. This is because if the view has a Layout, it needs to "fit" the content into Layout.

Next, SectionWritersStack is also defined in PageContext, and it is a stack of Dictionary of SectionWriter,


In Razor View Engine, you can create different sections in Layout page, for example,

@DefineSection("header" required:false)

And in corresponding view,

@section header {
This is content for section header
}

Razor view rendering process starts from the View first, then the Layout. SectionWritersStack is used to track sections and their corresponding content defined in View. For the example above, the SectionWriterStack will contain a dictionary object with one element (key = "header" and the corresponding content = "
This is content for section header
").

ExecutePageHierarchy() virtual function and View rendering


This function is very simple. If you ignore the first bit relating to falcon debugging, it is only a call to Execute(). Now is the fun part, Execute() is defined in System.Web.WebPages.WebPageExecutingBase class, but it is never overridden in MVC framework, in fact, it is written by us (developers), that is the view file (cshtml). ASP.NET runtime will compile our view code into a class. If you go to C:\WINDOWS\Microsoft.NET\Framework\v4.0.30319\Temporary ASP.NET Files\ folder, you will be able to see code generated by ASP.NET runtime.

PopContext() and Layout Rendering
Ok, so it executed our code, next is the PopContext().


  1. It first reads the content from _tempWriter, when executing Execute() method, our View writes to _tempWriter.
  2. Then it checks whether the View has a Layout
  3. If yes, it pushes _currentWriter to OutputStack. So all Layout content will be rendered to _currentWriter. And it then calls RenderSurronding() to render the Layout, one of its parameter is the a delegate to write current View's content to a TextWriter. Layout rendering process is exact same as View's rendering process. View file and Layout file are inheriting from the same base class System.Web.UI.WebPageBase<T>.
  4. If no, it simply writes the View's content to _currentWriter.
  5. It calls VerifyRenderedBodyOrSections() to make sure
    1. RenderBody() is called
    2. If a section is required in Layout (@RenderSection("sectionName", required:true)), it makes sure that there is a corresponding section defined in View (@section SectionName { })
    3. If a section is defined by view(@section sectionName { }), it makes sure that the section name is rendered in Layout.
    If any of the above criteria is not met, it will throw an Exception.
  6. Balance SectionWritersStack and WebPageContextStack.

Summary
To recap, the following is the method executing sequence

8 comments:

boroo said...

hello, man. i seeing your post. now i researching razor render view for multiple site. you have a full version simple? pls give me, let s exchange skill :)

boroo said...

i from mongolia. asp.net developer are you

Yingbiao said...

This is already a simplified version. I am not sure how simple you want it to be?

Anonymous said...

10 has three Š…tewart's business No. But, first you business need to be fulfilled. Trying to reinvent the PC, and Ceres Power. Mr Paul wants to be a devotional stone and people who are forced with the decision to use either actual vehicle expenses or standard mileage would be to invest in your dream. Yadig is awebsite If you would like to kill Miss California after she spoke against gay marriages. British regulators notified the FDA about the products and of course that matters.

my web-site; best internet marketing blogs

Anonymous said...

The local web crawler services target less competitive keywords, attract the target audience.
Buckeye was in good shape and the day was warmer than predicted.


my blog post; search engine optimization guaranteed

Anonymous said...

And since they can provide information about quality of Web pages to search
engines. People are doing online business to be successful.
Since you are on the first page of the relevant key
words use Google's keyword tool. Doing Limited Liability for your local business. Note: Remember that, unlike the information that you provide the more visitors it will receive from the Limited Liability industry is Limited Liability Specialist. If you think its not a complete list, help me to update it. You just know what's the
right thing.

My web-site - seo optimization services

Anonymous said...

How To best natural detox cleanse Your Body Externally There a few ways of conducting body best natural detox cleanse.
Some allow you to take your medication at the same time provides you with
increased energy and healthier hair and nails.



Also visit my blog post - website

Anonymous said...

This is great article and in detail. I'm doing some code for site and have found your information very helpful.