Introduction
As we all know, the UI
of the website is rendered by web browsers. And the web browsers create kinds of controls depends on the HTML
code provided by the website. So, when we visit a website, the web browsers will try to get the HTML
code of the website and the relative sources it needed according to Http
protocol, then the browsers will create and render all the controls in this website correctly.
The View
in the ASP.NET MVC
determines the rendering of the website. And we can notice that the name of View
is the same as Action
‘s name. When an Action
is executed, the ASP.NET MVC
will get the View
as a result by the name of the Action
. Then the View
will be translated into HTML
code and sent to browsers as a return.
So, the rendering in the ASP.NET
is about how to create the correct HTML
code.
Here is the code of a simple Action
.
1 | public ActionResult Index() |
In this method, it returns a ViewResult
as a result. And how does it work? How does the ASP.NET
find the correct view? And how to translate it into HTML code?
I will try to figure out the first question in this article (part one). And we will discuss the second question in my next blog (part two).
Details
All the source code about the ASP.NET
is provided by Microsoft. And the code is posted on the Github
, for more detail, visit AspNetWebStack.
Controller
The Controller
class inherits the ControllerBase
class. And here is the source code of the Execute
method in the ControllerBase
class.
1 | protected virtual void Execute(RequestContext requestContext) |
And as the code shows, when the Execute
method is executed, it will call the ExecuteCore
method which is an abstract method and this method is implemented in the Controller
class which is the only subclass of ControllerBase
.
Here is the source code of ExecuteCore
in Controller
class.
1 | protected override void ExecuteCore() |
It is easy to notice that there are four steps in the ExecuteCore
method.
- Load temp data
- Get the name of action by the
RouteData
- Call the
ActionInvoker.InvokeAction
method to execute the action which’s name is equal to theactionName
. - Save temp data
And what does ActionInvoker.InvokeAction
do? How does it translate the ActionResult
into the HTML
code? Reading the source code with these questions, I found that in the InvokeAction
method it calls ActionResult.ExecuteResult
after getting the result from the action method.
1 |
|
So, I guess that the secret of how does ASP.NET
translate the ActionResult
into Html
code is in the implementation of ActionResult
class and its subclasses.
ViewResult
What does the ActionResult
look like? What does the ExecuteResult
method do? Let’s see the code of ActionResult
class.
1 | public abstract class ActionResult |
The ActionResult
is an abstract class and the ExecuteResult
method is an abstract method too. Obviously, the correct implementation is in the subclass. So, I read the ExecuteResult
method in the ViewResultBase
class which is the base class of ViewResult
and inherits the ActionResult
class.
1 | public override void ExecuteResult(ControllerContext context) |
After reading this method, I am sure that this method is the core of translating the view into HTML. And there are 4 steps.
- If the
ViewName
is empty, it will set the name ofAction
as view’s name. - Find the correct
View
instance depends on thecontext
- Call the
Render
method of theView
instance to write the content of theView
into the information of theHttpContext
, and then return it to the browser. - Release the
view
‘s data
So, we can split the translation into two parts. The first part is to find the correct View
. And the second part is to translate.
How to find the correct view
The View
files are named with the name of the action
method, and these files are always placed in the directory which is named with the name of the Controller
class. And this directory will be placed in the View
directory in the root directory.
How does the ViewResult
find the correct View
?
Here is the source code of FindView
method in the ViewResult
class.
1 | protected override ViewEngineResult FindView(ControllerContext context) |
We can see from the code that the FindView
method calls ViewEngineCollection.FindView
method to find the View
with the ViewName
and MaterName
. If the View
is found, this method will return a ViewEngineResult
instance, if not the ViewEngineResult.FindView
will throw an InvalidOperationException
exception.
And there are two classes we have not seen before. One is the ViewEngineCollection
class and the other is the ViewEngineResult
class. So, let’s continue reading the code of these classes to figure out what do they do.
ViewEngineCollection
After reading the code about ViewEngineCollection
, I found that all of the instances of ViewEngineCollection
are managed by a static class named ViewEngines
. And the code in ViewEngines
is quite simple.
1 | public static class ViewEngines |
It is easy to find that there are two special classes in the code, WebFormViewEngine
and RazorViewEngine
. In the MVC
application, we use the RazorViewEngine
class to render the View
.
Here is the inheritance map of the WebFormViewEngine
and the RazorViewEngine
.
We can get some information from this picture.
- Their base class is
BuildManagerViewEngine
class, it means that these two classes are associated with building or compiling. - The base class of
BuildManagerViewEngine
is theVirtualPathProviderViewEngine
, it tells us that these two classes are based on the relative path to manageView
.
In this article, we are talking about ASP.NET MVC
. So, we ignore the WebFormViewEngine
and continue reading the code of RazorViewEngine
.
1 | public class RazorViewEngine : BuildManagerViewEngine |
It is important to notice that there is a magic string named ViewStartFileName
, and its value is _ViewStart
. So, it means the _ViewStart
is the start page without changing. And we can see that the RazorViewEngine
class set lots of location format strings when it is initializing, and these formats specify the search path for the pages.
Finally, I found the implementation of the FindView
method in the VirtualPathProviderViewEngine
class.
1 | public virtual ViewEngineResult FindView(ControllerContextcontrollerContext, string viewName, string masterName, bool useCache) |
And there are 4 steps to create an instance of the ViewEngineResult
.
- Find the correct name of the controller by the
RouteData
- Get the file path of the
View
by passing theviewName
,masterName
andcontrollerName
into theGetPath
method - Get the master’s file path by calling
GetPath
method - New an instance of
ViewEngineResult
and return it
And the GetPath
method needs the LocationFormats
we mentioned above to find the correct path.
Conclusion
Overall, we probably know that how does ASP.NET MVC
finds the correct View
file. When a Controller
instance is executed, it will call ActionInvoker.InvokeAction
method to execute the correct Action
by the actionName
. And in the ActionInvoker.InvokeAction
method, it calls ActionResult.ExecuteResult
method, in this method the ViewResult.FindView
method is called to find the correct View
. And after reading the code about RazorViewEngine
and ViewEngineCollection
we can know that the RazorViewEngine
set lots of location formats to help the VirtualPathProviderViewnEngine.FindView
method to find the correct View
by relative path.