ASP.NET has no magic-ASP.NET MVC Razor and View rendering

ASP.NET has no magic-ASP.NET MVC Razor and View rendering

For a web application, its interface is rendered to the user by the browser based on the HTML code and related resources referenced by it. In other words, the interface rendering of the web application is done by the browser, and the web application The principle is to obtain the corresponding Html code and related resources from the server through the Http protocol, so that the browser can complete the correct rendering work.

ASP.NET MVC as a Web application construction framework View assumes the function of UI display. During the development process, View is named after Action. When a user's request is routed to a certain Action method, ASP.NET MVC will follow the Action To obtain the corresponding View file, dynamically process the View file to generate the final Html content, and return the content to the browser for display. So ASP.NET rendering actually refers to the process of dynamically generating Html code.
The code of action in ASP.NET MVC can be as simple as the following:

You only need to call a View method to display the Index View on the user's browser. So what exactly does the View method do? What is Razor? What is the return value of the Action method, ActionResult?
This article will introduce the ASP.NET MVC Html code generation process from the following aspects:
ActionResult and ViewResult
View lookup and Razor
View compilation and activation
View rendering
Demonstrating View using sample code Rendering process
View Html Helper and ModelMetadata
Commonly used ActionResult

ActionResult and ViewResult

As mentioned in the previous article "ASP.NET No Magic-ASP.NET MVC Filter (Filter)", the Action method is executed by the ActionInvoker, and the result returned by the Action is an ActionResult type. After the Action is executed, the ActionInvoker again The ExecuteResult method of ActionResult is called to complete the specific operation. The relevant code is as follows:

The definition of ActionResult is as follows. It contains a method named ExecuteResult, which is used to process the execution result of the action method:

Back to the View() method mentioned at the beginning, the method is defined in the Controller, and its return value is a ViewResult type:

It can be said that when the Action is executed, the View rendering of ASP.NET MVC is completed by ViewResult in the ExecuteResult method. The ExecuteResult implementation code of ViewResult is as follows (Note: This code is implemented in the ViewResult base class ViewResultBase):

It can be easily seen from the code that there are four main steps in the rendering of View in ASP.NET MVC:
1. If the name of the View is not specified, then the name of the Action is the name of the View by default.
2. Find and obtain the real View object according to the context of the controller.
3. Call the Render method of the View object to write the content of the View into the response message of the HttpContext, and then return it to the browser.
4. Release the View object.

According to the above analysis, the two important steps of View rendering are the search and rendering of View objects . The entire process can refer to the following figure. The details will be introduced later:

View search and Razor

In ASP.NET MVC, the View file is generally placed in the Views directory of the project root directory, with the Controller name as the subdirectory, and each subdirectory stores the View file named after the action method:

The code to find View in the ViewResult type is as follows:

It can be seen from the code that it uses a ViewEngineCollection object to find View according to ViewName (the default is actionName). If it finds a ViewEngineResult type, it will throw an exception, which contains the location of the search:

  Note: From the above error message, you can see that when ASP.NET MVC is looking for View, in addition to matching the .cshtml and .vbhtml files, it also matches the .aspx and .ascx files, the latter is the Web Form framework Page file, why is this? Because ASP.NET MVC contains the Razor engine used by MVC and the Web Form engine used by Web Form by default, in the case of pure MVC development, in order to optimize performance , the Web Form engine is generally deleted by the following code :

More View engine content will be introduced later.


There is an IViewEngine interface in ASP.NET, which defines the search and release of View, which is defined as follows:

The type relationship of the IViewEngine interface implemented in ASP.NET is as follows:

The following information can be obtained from this figure:
There are two finally implemented ViewEngines in ASP.NET, namely Razor and WebForm. In MVC applications, Razor is used to achieve View rendering.
Their base classes are all VirtualPathProviderViewEngine, which means that they are all based on relative paths to manage View.
Their base classes are BuildManagerViewEngine, and on the surface they are all related to compilation (Note: In ASP.NET, whether it is WebForm or MVC, you can write code on the page, and these codes are definitely not understood by the browser. It can work normally after compilation).

ViewEngine in ASP.NET is managed by a collection called ViewEngines, as shown in the following figure:

RazorViewEngine is mainly used in MVC. The following figure shows part of the code of RazorViewEngine:

Two important information can be seen from the code. The first is that "_ViewStart" is hard-coded as the startup page , which is why the layout is specified on this page. In addition , various LocationFormats are hard-coded in the construction method. They specify The search path of the corresponding type of page is shown .

So what is Razor mentioned above? Razor is a markup language of ASP.NET that can embed server code into web pages. It consists of Razor markup, server code (C#/VB) and Html code . The content starting with the @ symbol in Html will be recognized as server code, and Razor will recognize these codes and render them as Html code. For more information about Razor, please refer to:


ViewEngineResult is the encapsulation of ViewEngine's search results for View, which is defined as follows:

It contains the type of IView after the search and the ViewEngine itself used for the search. In addition, there is a list of strings used to save the path traversed to search for the View.
The following is the main code used by RazorViewEngine to find and create RazorView objects. The core is actually the process of finding whether the file exists after matching the action name and Controller name with the corresponding LocationFormats, and creating an IView instance if it exists:

And the IView type here is RazorView:

View compilation and activation

The above introduced the ViewEngine used to find and obtain the corresponding IView object, what is the IView used for? The following figure is the interface definition of IView. It has only one Render method, which is used to render the specified View context information through the specified TextWriter. This is actually the process of processing the content of the View file and writing to the Http response data:

The class structure for implementing IView in ASP.NET is as follows:

There are also two kinds of View objects Razor and WebForm, and their base classes are BuildManagerCompiledView (View compiled by BuildManager), and the Render method is also implemented in the base class. The specific code is as follows:

The RenderView method is implemented in the corresponding subclass. The following figure shows the RenderView method of RazorView:

The core of the above code is:
1. The View file is compiled according to the path of the View file through BuildManager, and the compiled type is obtained (Note: BuildManager is a tool used to compile assemblies and pages in ASP.NET).
2. Create View compiled types through the activator. The following figure is the default activator. The core is to directly create type instances by relying on the parser or Activator.

3. The instantiated object is a WebViewPage type, which is rendered by calling the ExecutePageHierarchy method of WebViewPage after initializing the WebViewPage (including the search for the starting page).

Note: WebViewPage is the page type corresponding to Razor, and WebForm corresponds to ViewPage and ViewUserControl.

View rendering

As mentioned above, the View file is compiled into a WebViewPage object, and the rendering of the View is also done by this object, so what is WebViewPage? The following figure is the definition of WebViewPage:

It can be seen that some important attributes such as Html, Ajax, Url, etc. can be used in the View. There are help types used to generate Html, Url, Ajax, and it is also like the Model, which carries data and binds to the View. TempData, ViewBag, ViewData and other types.
In addition, WebViewPage inherits to WebPageBase:


Methods such as RenderBody and RenderSection are defined in the WebPageBase type.
After understanding WebPage and WebPageBase, do you feel that the View file is actually a subtype of WebPage, and you can use and call the properties and methods in WebPage and WebPageBase at will in View.
The following figure is the compiled code of Contact.cshtml file:

The previous guess is proved from the code, the View file is indeed a subtype of WebViewPage after compilation, and the Execute method in this type is to splice the Html code in the form of a string. If you encounter a special method call during the splicing process Then the return value of the splicing special method:

The above code comes from the compilation result of the layout file.
The Execute method is the actual method of View rendering in the final ASP.NET MVC. The ExecutePageHierarchy of WebViewPage is because the page in MVC may depend on multiple Views. For example, the page has the layout view and content view specified in StartPage by default. In order to ensure that the rendering content order remains unchanged, the ExecutePageHierarchy method introduces a stack mechanism (last in, first out).

Note: The default path of the View result compiled by BuildManager is "%WinDir\Microsoft.NET\Framework/{Version No}\Temporary ASPNET Files". The assembly starts with App_Web_. The name of the assembly is randomly generated based on the path. of.

Use sample code to demonstrate the rendering process of View

The following code is used to demonstrate the whole process of View search, compilation, activation and rendering:

Full code:

1 using System; 2 using System.Collections.Generic; 3 using System.IO; 4 using System.Linq; 5 using System.Web; 6 using System.Web.Compilation; 7 using System.Web.Mvc; 8 using System.Web.WebPages; 9 10 namespace My_Blog.Controllers 11 { 12 public class ViewRenderController: Controller 13 { 14//GET: ViewRender 15 public void Index() 16 { 17 var path = ""; 18 var viewEngineResult = this.FindView(out path);//Find View 19 Render(viewEngineResult, path);//Render View 20} 21 22//View search, equivalent to RazorViewEngine 23 private ViewEngineResult FindView(out string path) 24 { 25 var actionName = "Contact"; 26 var controllerName = "Home"; 27 var viewLocationFormat = @"~/Views/{1}/{0}.cshtml"; 28//Compose View relative path according to Controller and Action name and address template 29 path = string.Format(viewLocationFormat, actionName, controllerName); 30//Create RazorView and ViewEngineResult according to the file path 31 var view = new RazorView(this.ControllerContext, path, "", true, null, null); 32 return new ViewEngineResult(view, new RazorViewEngine()); 33} 34 35//View rendering 36 private void Render(ViewEngineResult viewEngineResult,string path) 37 { 38 Type pageType = BuildManager.GetCompiledType(path);//Compile according to the View file 39 var pageInstance = Activator.CreateInstance(pageType);//Create View file compiled type instance 40 var webViewPage = this.InitViewPage(pageInstance, viewEngineResult, path);//Initialize the relevant attributes in the instance 41 webViewPage.ExecutePageHierarchy(//Complete the rendering of View 42 new WebPageContext(this.HttpContext, null, null), 43 this.HttpContext.Response.Output, null);//startpage is set to null, the layout page will not be rendered 44} 45 46 private WebViewPage InitViewPage(object instance, ViewEngineResult viewEngineResult, string path) 47 { 48 WebViewPage webViewPage = instance as WebViewPage; 49 50 if (webViewPage == null) 51 { 52 throw new InvalidOperationException("Invalid"); 53} 54 ViewContext viewContext = new ViewContext(this.ControllerContext, 55 viewEngineResult.View, 56 this.ViewData, 57 this.TempData, 58 this.HttpContext.Response.Output); 59 webViewPage.VirtualPath = path; 60 61 webViewPage.ViewContext = viewContext; 62 webViewPage.ViewData = viewContext.ViewData; 63 webViewPage.InitHelpers(); 64 return webViewPage; 65} 66} 67} Copy code

View Code

The key points of the above code are as follows:
The FindView method actually represents RazorViewEngine. It obtains the full path of the View file according to the hard-coded View file search template and the names of Controller and Action, and creates RazorView and ViewEngineResult objects.
Render represents the compilation, activation and rendering process of View.

  Running results (because there is no layout page, so related styles and JS are not introduced):

View Html Helper and ModelMetadata

In ASP.NET MVC View, some Helper types can be used to generate HTML code. The following figure shows the View code of the user registration page:


From the code, you can see that ASP.NET MVC does not completely use Html to form the page. There are some methods called through the Html attribute (Note: Html is an instance of the HtmlHelper type in the WebViewPage type). From the method name These methods are respectively used to generate HTML codes such as data verification information, Label tags, text boxes, and password type text boxes.
ASP.NET MVC provides a series of Helper classes and their extension methods. These Helper classes encapsulate HTML and Ajax (for the usage of Ajax Helper in ASP.NET MVC, please refer to: ) and other related content, ASP.NET MVC's Html extension can be divided into the following four categories:
1. Extensions used to generate specific labels, such as Form, Input, Label, TextArea, Select and other extensions.
The usage is as follows:

Encapsulate commonly used HTML tags. For developers who are not familiar with Html, ASP.NET MVC provides a way of object-oriented programming to develop pages. More importantly, the Html method can be associated with the model. When there are corresponding verification features in the metadata and client-side verification is turned on, the corresponding verification information will be included when rendering tags. The biggest advantage of using this type of tag is that you can focus all on the model, and when the model changes No modification is required on the View.

2. The extension used to generate Model verification information.
The usage is as follows:

ASP.NET MVC provides a model verification mechanism. When model verification fails, there will be corresponding failure messages. The extension is to render these error messages, which greatly reduces the workload of outputting verification information.

3. According to the purpose of "display/edit" to generate the Display and Editor extension of the label.
The usage is as follows (Note: DisplayFor is used to display the value in the specified model attribute, if you want to display the name of the corresponding model attribute, you can use DisplayNameFor):

Display and Editor determine how to display the model based on the data type of the model. ASP.NET MVC provides some basic types of default template implementations for Display and Editor, which are stored through the internal static types DefaultEditorTemplates and DefaultDisplayTemplates. The following is the bool type template code:

While providing default templates, ASP.NET MVC also provides a mechanism for customizing templates. You can use DisplayAttribute and UIHintAttribute to specify rendering templates for specific attributes. For how to customize Display and Editor templates, please refer to:

4. Partial expansion.
Usage (Note: The first parameter is the name of the Partial View. By default, the Partial View file is stored in the Views/Shared directory. If the file is not in this directory, you need to reflect the specific directory in the parameter):

Partial is a mechanism for separating reusable Html in ASP.NET MVC, and Partial can access data, that is to say, Html code separated by parital can dynamically generate Html code according to the incoming data, more about For the content of Partial View, please refer to the documentation of .Net Core:

5. Child Action expansion.

Child Action is similar to Partial View. It also separates the reusable parts, but Partial View focuses more on Html code reuse. Child Action also includes the reuse of back-end logic. For example, the shopping cart of a shopping website, it may appear on any page, but the logic and model of the home page may not have any relationship with the shopping cart. At this time, Child Action can be used.

Commonly used ActionResult

As mentioned earlier, the page rendering work of ASP.NET MVC is actually completed by a ViewResult object inherited from ActionResult. ActionResult is actually an abstraction in ASP.NET MVC and represents the result of all logic execution, while ViewResult The result is human-oriented, so Html is returned for the browser to display to people. In addition to ViewResult, there are some commonly used ActionResults as follows:
ContentResult: used to return a string to the client, and call Content in the Action method The method returns.
FileStreamResult: used to return the file to the client, call the File method (with multiple overloads) in the Action method to return.
HttpNotFoundResult: used to return the HTTP not found status, call the HttpNotFound method in the Action method to return.
JavaScriptResult: Used to return JavaScript to the client and execute it, and call the JavaScript method in the Action method to return.
JsonResult: used to return Json data to the client, and call the Json method in the Action method to return.
PartialViewResult: used to render the partial page, call the PartialView method in the Action method to return.
RedirectResult: used for redirection. In the Action method, call the Redirect method to pass in the Url that needs to be redirected for redirection.
RedirectToRouteResult: used for route redirection, call RedirectToAction method in Action method to redirect to the specified Action.
EmptyResult: return empty, return Null in the Action method or set the return value of the Action method to Void.


This article introduces how ASP.NET MVC completes the process of finding, compiling and rendering View files through the execution of ActionResult (ViewResult) when the Action method is executed. In addition to ViewResult, ASP.NET MVC also provides other types of ActionResult such as Json , File, etc., using these results can create simple Web API and file downloading functions. In addition, MVC expands the View through the Html Helper type. When developing the View, the Html code and logic of the View can be reused to the greatest extent, and at the same time Also associate the View with the Model (specifically ViewModel), you can focus on the Model during development, without worrying about the modification of the View code after the Model is modified. Reasonable use of the related mechanisms provided by View can greatly reduce the workload and also make the code more concise.

Reference: ...

 Link to this article: 

ASP.NET has no magic-directories