Yingbiao's Blog
Focusing on .NET
Tuesday 6 December 2011
T4 template solves Linq-to-SQL and String or binary data would be truncated error.
We have a few options to fix the issue, but we created a T4 template that would automatically truncate the string if it is too long. Here is the code.
Thursday 16 December 2010
Dive deep into ASP.NET MVC Razor view rendering process
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
- It firstly saves parameter "writer" to _currentWriter and also the context information. The parameter "writer" is HttpContext.Response.Output object from ViewResultBase.ExecuteResult()
- It then creates a TextWriter (_tempWriter) object and pushes it to the OutputStack.
- It then pushes a new Dictionary object to SectionWritersStack
- 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 {
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 = "
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().
- It first reads the content from _tempWriter, when executing Execute() method, our View writes to _tempWriter.
- Then it checks whether the View has a Layout
- 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>.
- If no, it simply writes the View's content to _currentWriter.
- It calls VerifyRenderedBodyOrSections() to make sure
- RenderBody() is called
- 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 { })
- If a section is defined by view(@section sectionName { }), it makes sure that the section name is rendered in Layout.
- Balance SectionWritersStack and WebPageContextStack.
Summary
To recap, the following is the method executing sequence
Tuesday 30 November 2010
@Html.RenderAction caused StackOverflowException
_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.
CauseThe 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.
FixThe 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
I have re-structured the IRepository
The IRepository
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
Creating the Entity Framework model
Installing POCO Entity Generator Extension
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.
Wednesday 28 April 2010
Memcached
Memcached 网站
http://memcached.org/