Understanding of MVC Page Life Cycle
When you invoke an action in an MVC application, everything happens as if you were simply calling a method in the controller class. How do we go from an http request to a method invocation with arguments? I will try here to describe everything that happens during the MVC request processing. How and why everything is done? A little trip deep into the framework always useful to find some pretty solutions to recurring problems.
Let’s look at each steps in detail. I have put some code as well to understand a little better how everything works in MVC.
Step 1: Routing
In ASP.NET application each asp.net page implements the IHTTPHandler interface.
This interface has a ProcessRequest() method that gets called when you request the page. The ProcessRequest() method is responsible for processing the request and generating the response. So in asp.net application it is simple, you request for a page in the url like https://mysite1\default.aspx and then it search for that page on the disk and execute the processrequest method and generate the response.
However in MVC application it doesn’t work in that way. There is no physical page exist for a particular request. All the requests are routed to a special class called Controller. The controller is responsible for generating the response and sending the content back to the browser.
When you build a MVC application you can define a bunch of controllers. Each controller can handle multiple requests. For example, all the following will route to same Controller.
These requests will execute the same Controller Controller1 and in that it will extract the id from the URL and process the request. This gives more readable URL then asp.net page.
So how these requests are routed to particular controller. Now the RouteTable come into the picture. Every ASP.NET MVC application has a RouteTable. This routetable is responsible to map the mvc requests to particular controller.
public class MvcApplication : System.Web.HttpApplication
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
}
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterRoutes(RouteTable.Routes);
}
}
}
Whenever the Application Start the Application_Start events will get called and it will call the method RegisterRoutes which will send the collection of Routes as the parameter and the routes will be added to this Collection which is a Dictionary of NamedMaps.
Each route also references a handler which will handle the rest of the request. When we use MapRoute, what we really do is creating a route by instantiating the 3 dictionaries and defining the default MVC handler: PageRouteHandler. Each RouteHandler implements an interface IRouteHandler.
public Route MapPageRoute(string routeName, string routeUrl, string physicalFile, bool checkPhysicalUrlAccess, RouteValueDictionary defaults, RouteValueDictionary constraints, RouteValueDictionary dataTokens) { if (routeUrl == null) { throw new ArgumentNullException("routeUrl"); } Route item = new Route(routeUrl, defaults, constraints, dataTokens, new PageRouteHandler(physicalFile, checkPhysicalUrlAccess)); this.Add(routeName, item); return item; } Step 2: The URL Routing Module intercepts the request. Whenever you make a request against an ASP.NET MVC application, the request is intercepted by the UrlRoutingModule HTTP Module. When the UrlRoutingModule intercepts a request, the first thing the module does is to wrap up the current HttpContext in an HttpContextWrapper object. The HttpContextWrapper object derives from HTTPContextBase class.
private void OnApplicationPostResolveRequestCache(object sender, EventArgs e) { HttpApplication application = (HttpApplication) sender; HttpContextBase context = new HttpContextWrapper(application.Context); this.PostResolveRequestCache(context); } Then the module send this contextBase object to the method called PostResolveRequestCache . Based on the Context it will return the correct RouteData from the RouteTable which was created in the earlier step based on the URL, form parameters and query string parameters associated with the HTTPContext object. If the UrlRoutingModule successfully retrieves a RouteData object then the module next creates a RouteContext object that represents the current HttpContext and RouteData. The module then instantiates a new HttpHandler based on the RouteTable and passes the RouteContext to the new handler’s constructor. In the case of an ASP.NET MVC application,the handler returned from the RouteTable will always be an MvcHandler. This MVCHandler also derive from interface IHTTPHandler and implement the method ProcessRequest(). The last step is it will call the RemapHandler method which will set the MVCHandler just obtained to be the Current HTTP Handler.
public virtual void PostResolveRequestCache(HttpContextBase context) { RouteData routeData = this.RouteCollection.GetRouteData(context); if (routeData != null) { IRouteHandler routeHandler = routeData.RouteHandler; if (routeHandler == null) { throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, SR.GetString("UrlRoutingModule_NoRouteHandler"), new object[0])); } if (!(routeHandler is StopRoutingHandler)) { RequestContext requestContext = new RequestContext(context, routeData); context.Request.RequestContext = requestContext; IHttpHandler httpHandler = routeHandler.GetHttpHandler(requestContext); if (httpHandler == null) { throw new InvalidOperationException(string.Format(CultureInfo.CurrentUICulture, SR.GetString("UrlRoutingModule_NoHttpHandler"), new object[] { routeHandler.GetType() })); } if (httpHandler is UrlAuthFailureHandler) { if (!FormsAuthenticationModule.FormsAuthRequired) { throw new HttpException(0x191, SR.GetString("Assess_Denied_Description3")); } UrlAuthorizationModule.ReportUrlAuthorizationFailure(HttpContext.Current, this); } else { context.RemapHandler(httpHandler); } } } }
Step 4: MVC Handler Executes MVCHandler also inherit from the IHTTPAsyncHandler. When MVC Handler executes it will call the BeginProcessRequest method of the httpAsyncHandler asynchronously. When the process request method is called a new controller gets created. The controller is created from a ControllerFactory. There is a ControllerBuilder Class which will set the ControllerFactory. You can create your own ControllerFactory as well but by default it will be DefaultControllerFactory. The RequestContext and the name of the Contoller will be passed to the method CreateController Method to get the particular Contoller.
|
Comments
Anonymous
October 03, 2013
best explanation I already readAnonymous
October 03, 2013
Can you replace the image for a clearer one?? Stretching it has pixelated it badly. Cheers, -- LeeAnonymous
October 03, 2013
maybe article is good, but image is bad, code formating is bad ,how can i read? please change the image and formate code, thank youAnonymous
October 03, 2013
Great explanation but the code needs to be formatted. Also, sharing a better image would be a plus; I would like to be able to print a good copy for reference.Anonymous
October 04, 2013
Same as above, could be a great article but why should I expend any effort reading it, when you've put little into formatting it!Anonymous
October 06, 2013
you are microsoft employee???? pratiktips.blogspot.de/.../the-magic-of-aspnet-mvc-model-binding.htmlAnonymous
October 06, 2013
Could you compress that image a bit more.. Its too crisp.Anonymous
October 07, 2013
Better image URL: 4.bp.blogspot.com/.../image.pngAnonymous
November 05, 2013
Its really good to understand MVC Page life cycle. ThanksAnonymous
February 27, 2014
Impossible to read due to formatting(((Anonymous
March 29, 2014
I read this article today and owe my understanding of MVC page life cycle to this article. But I have a little confusion that I would like to clarify (quoting the first stanza of the fifth point): "The Controller typically either executes either the RedirectToAction Method or the RenderView Method. When you call a controller’s RenderView() method,the call is delegated to the current ViewEngine’s RenderView() method." "When you call a controller' RenderView" but there is no RenderView method in controller class, so where does this method actually belong to?Anonymous
June 02, 2014
Its quite confusing overall. When i started learning MVC Page life cycle I started with this article but very soon I realized that the stuff mentioned here is not right. MVC handler is termed as PageRouteHandler, (it must be MVCRouteHandler) MappRoute is termed as MapPageRoute. This article is merely a copy paset from following URL's, even not done properly stephenwalther.com/.../asp-net-mvc-in-depth-the-life-of-an-asp-net-mvc-requestAnonymous
October 07, 2014
how can I see the code snippets? I mean what is/are the dll(s) for these code?Anonymous
June 04, 2015
Fabulous !! Agreed that the formatting needs to improve and all , yet great article. VERY HELPFUL !!Anonymous
June 25, 2015
I think this is the one of the best articles on this topic. Thanks Varunm!