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

Tuesday 30 November 2010

@Html.RenderAction caused StackOverflowException

Background

_Layout.cshtml file uses @Html.RenderAction(“Menu”, “Nav”) to render the menu.


And the NavController has the following code

By doing so, we can generate menu dynamically. But the above code throws an exception: StackOverflowException, the code is working perfectly using WebFormViewEngine, but is not working for RazorViewEngine.

Cause

The cause of the above exception is the newly introduced "_ViewStart.cshtml" file. The code inside "_ViewStart.cshtml" will run before rendering any view, and currently the content of _ViewStart.cshtml is very simple,

It just set the current layout. As NavController's Menu() action simply returns View(), it causes "_ViewStart.cshtml" to kick in, which in turn renders _Layout.cshtml again, which call Html.RenderAction("Menu", "Nav") again, thus causes infinite loop and eventually throws StackOverflowException.

Fix

The fix to the above error is very simple, just change the NavController's Menu() action as follows will fix the issue, because PartialView() will not execute "_ViewStart.cshtml" file, hence avoids the infinite loop.

Wednesday 10 November 2010

ASP.NET MVC3 Release Candidate

Today, ASP.NET team just announced the ASP.NET MVC 3 Release Candidate, you can download it from Microsoft download center.

It includes a bunch of new features and makes ASP.NET MVC development much easier. The main change compare to Beta version is the Razor Intellisense within Visual Studio. The RC support colorization and intellisense for the new Razor view engine. Intellisense works with HTML, C#, VB, Javascript and CSS. 

Wednesday 6 October 2010

Applying Generic Repository and Unit of Work Pattern to Entity Framework

There is a very good article (Testability and Entity Framework 4.0) talking about the Repository and Unit of Work pattern and how we can do that using Entity Framework. However, I don't like the way the IRepository and IUnitOfWork were designed. Firstly the IRepository interface has too many unnecessary methods and some are based on assumption, for example FindById(int id), what if an entity uses GUID as primary key? Also the FindAll() and FindBy() methods are returning IEnumerable which will cause the lambda expression to be evaluated when returned from these methods. Secondly the IUnitOfWork has reference to all repositories, what if we add a new repository, do we have to update the IUnitOfWork interface? I think this is a bad design.

I have re-structured the IRepository and IUnitOfWork interfaces as follows,




The IRepository interface will have Add(), Delete() and Attach() method to track entities, it also has a readonly reference to IUnitOfWork to Commit(), and there is another readonly properties "Entities" which is of type IQueryable, so that it can be queried using LINQ. We don't really need methods like FindById() defined in the interface as they be easily added using extension methods.

Two concrete implementation for Entity Framework,


Using the EFRepository and EFUnitOfWork in MVC



To save a new event,


Simple and elegant.

Wednesday 22 September 2010

Using POCO in Entity Framework 4

Introduction
The entity classes that are generated from Entity Framework inherit from System.Data.Objects.DataClasses.EntityObject, Entity Framework version 1 was blamed for lake of support for testability. The current Entity Framework V4 now supports POCO classes. This post shows how you can do that. Please note that you need Visual Studio 2010, the express edition will do.

Database Schema
This example uses an simple Event Booking system with the following three tables.



Creating the Entity Framework model
The first step is to create a cenceptual model. In the visual studio, add one item "ADO.NET Entity Data Model", follow the wizard and select all tables, the end result is as follows. Please note, that the EventBooking table is not in the model, instead, you can see two navigation properties. The Entity Framework is very smart to work out the relationship.


Turn off code generation from Entity Model
By default, the Entity Framework will generate code for you, but the default one is inherited from EntityObject and this is not what we want. So we are going to turn off the automatic code generation. Firstly click anywhere in the design view of Entity Model, then from the Properties window, change the Code Generation Strategy to "None", this will turn off code generation because we are going to use our POCO classes.


Installing POCO Entity Generator Extension
Next, you need to install one extension, go to Tools -> Extension, then go to Online Gallery, and install the ADO.NET C# POCO Entity Generator.

Generating POCO Entities
Now we are ready to generate our POCO entities. Add a new item to the project, a new entry "ADO.NET POCO Entity Generator" will be available.

Select that and name it "EventModel.tt", it will add two files "EventModel.tt" and "EventModel.Context.tt", the "tt" extension is the Microsoft T4 template.

Next open the "EventModel.tt" file and replace "$edmxInputFile$" with "EventModel.edmx" and save it, it will automatically generate entity POCO classes. Do the same with "EventModel.Context.tt". Now you can start using the POCO classes.

In the next post, I want to talk about generic Repository and Unit of Work pattern by using Entity Framework and POCO.



Wednesday 28 April 2010

Memcached

做网站开发已经很多年了,还是第一次听说Memcached,说起来有点孤陋寡闻。在以前的一个公司,为了提高网站的可伸缩性(Scalability),使用了各样的方法,包括对数据库进行优化,对应用程序代码进行优化,也对一些关键页面进行缓存(第一次访问的时候生成一个文件,然后下次访问的时候,直接读取文件而不用再次查询数据库,从而减少对数据库的读取,而且读文件相当的快。当有更新的时候,删除文件,这样下次访问的时候,又会自动生成新的缓存文件)。今天看到Memcached,有点异曲同工之处,不过区别是Memcached使用内存,速度更快,而且Memcached可以通过增加服务器来自动Scale Out。


Memcached 网站
http://memcached.org/