Charteris Community Server

Welcome to the Charteris plc Community
Welcome to Charteris Community Server Sign in | Join | Help
in Search

gopalk

How does ASP.NET MVC work – Part 2

In the last post we saw how an ASP.NET MVC request gets routed through to the MVC framework through the ASP.NET framework. We also saw that the MvcHandler class is the HttpHandler responsible for servicing an ASP.NET MVC-request. A simplistic view of the order in which routing and MVC classes come into play is like this:

UrlRoutingModule -> MvcRoutingHandler -> MvcHandler

So at this stage our request has got an HttpHandler assigned in the form of MvcHandler. Moving ahead in the HttpApplication event processing, the fulfilling of a request takes place when the ProcessRequest method on the MvcHandler gets invoked.

MvcHandler

  • Within the ProcessRequest method, the original HttpContext is wrapped into an HttpContextWrapper instance. HttpContextWrapper implements an abstract class called HttpContextBase.

Loose coupling: Within an ASP.NET MVC controller, HttpContext is referenced not directly but via this abstract HttpContextBase class. As evident, this enables loose coupling between your controller class and the HttpContextWrapper instance and thus improves testability by allowing you to easily mock your HttpContextBase class when performing unit tests. This loose coupling also extends to other objects like Request (referenced to via HttpRequestBase) and Response (HttpResponseBase). These abstract types are defined within a separate assembly System.Web.Abstractions.dll. This opens up the possibility of using them outside the MVC framework!

Compare this to a traditional WebForms Page, where the Page class references the HttpContext via a direct reference, and the HttpContext object is also sealed. So it’s difficult to mock HttpContext for testing purposes, thus making a WebForm page difficult to test. This is one clear advantage of ASP.NET MVC over traditional WebForms.

  • At this point we have two classes that carry information about the request. These are RouteData and HttpContextWrapper (Packaged up into RequestContext and assigned to MvcHandler earlier during the PostResolveRequest stage of the UrlRoutingModule). RouteData is a dictionary object containing key value pairs related to the matching route. The information RouteData will contain will typically be controller name, action name, route name, default parameter etc matching the current request. These are extracted from the parameters passed into the RouteCollection.RegisterRoute calls made in Global.asax:
       1: routes.MapRoute(
       2:     "Default", // Route name 
       3:     "{controller}/{action}/{id}", // URL with parameters 
       4:     new { controller = "Home", action = "Index", id = 1 } // Parameter defaults
       5: );

RouteData can also be used from within the Controller (via ControllerContext) and View (via ViewContext) to get the current route name, action name, controller name etc. Thanks to RouteData dictionary, at this point MVC knows the name of the controller and the action to be invoked.

ControllerFactory (DefaultControllerFactory)

  • Further in the ProcessRequest method, a controller must be located to fulfil the current request. To do this, a controller factory is acquired first. By default in ASP.NET MVC this is an instance of DefaultControllerFactory. In typical ASP.NET MVC fashion there is an extensibility point here too.

A controller factory must implement IControllerFactory interface and a custom controller factory can be registered to override the DefaultControllerFactory in Global.asax.

   1: protected void Application_Start() {
   2:     ControllerBuilder.Current.SetControllerFactory(<Your controller factory>);
   3:     ...           
   4: }

One of the reasons you would want to register a custom controller factory is, if you want your controllers to be instantiated by an IoC (Inversion of Control) container and injected with dependencies like Loggers etc dynamically. There is some more information on how to create a custom controller factory for ASP.NET MVC here: http://www.pnpguidance.net/Post/SetDefaultControllerFactoryIControllerFactoryASPNETMVCFramework.aspx 

The MVCContrib project on Codeplex makes available controller factory classes with support for various popular IoC frameworks like StructureMap, Castle Windsor, Unity Framework and Spring.NET: http://www.codeplex.com/MVCContrib

IController (Controller)

  • Once an instance of the controller is retrieved from the controller factory, Initialize method is called on the controller. This is an important part of the controller lifecycle which provides access to the request and is a good place to initialize properties on the controller.

IActionInvoker (ControllerActionInvoker)

  • Next the Execute method is invoked on the instance of Controller class and RequestContext is passed in as an argument. This sets off the controller lifecycle. An object of type IActionInvoker rather than the controller itself controls the order in which various methods on the controller and filters are executed.
       1: bool IActionInvoker.InvokeAction(ControllerContext controllerContext, string actionName)

(ControllerContext is composed of the RequestContext and Controller instance.)

Notice the separation of concerns and yet another point for extension. A custom implementation of IActionInvoker can be assigned to the Controller if we want our action invoker to do things a bit differently. The default implementation of IActionInvoker is ControllerActionInvoker class, and does quite a bit behind the scenes as we’ll see below:

    • First parameter values are obtained for the parameters on the action method. This is done by a ModelBinder. A ModelBinder is responsible for converting the data in request (i.e. form parameters, querystring parameters etc) into parameter values that an action method accepts. Of course, this is yet another extensibility point in the framework where a custom ModelBinder can be assigned to an action method via the use of attributes (Note the influence of AOP (aspect oriented programming) in the framework). The default ModelBinder is used if a custom ModelBinder is not specified. More information here on creating custom ModelBinders: http://www.singingeels.com/Articles/Model_Binders_in_ASPNET_MVC.aspx
    • Now the various filters are executed. Simply put, filters are interceptor methods that can execute before and after the action method execution. They allow you to separate cross cutting concerns or non-action-specific code from the code in the action method (Notice the nice use of AOP). There are different types of filters:
      1. Authorization Filter – IAuthorizationFilter interface
      2. Action Filter – IActionFilter interface
      3. Result Filter – IResultFilter interface
      4. Exception Filter – IExceptionFilter interface
    • Authorization Filter is the first set of filters to be executed. Processing can be halted within this stage by cancelling the action. This can be done by setting the cancel property on AuthorizationContext to true.In the code below, the further processing of the action is cancelled, the RedirectResult is executed which should result in a redirect to Login action. An authorization attribute can be implemented by deriving from AuthorizeAttribute (which implements IAuthorizationFilter) and applying the attribute to an action method. The Controller class itself implements IAuthorizationFilter, so the easiest way to implement an Authorization Filter is to override the OnAuthorization method inside your controller class.
         1: public override void OnAuthorization(AuthorizationContext filterContext)
         2: {
         3:     filterContext.Cancel = true;
         4:     filterContext.Result = new RedirectResult("/Home/Login");
         5: }
 
    • Action Filter – OnActionExecuting: If the processing isn’t cancelled above, then the OnActionExecuting method on the action filter collection is executed. Again as with Authorization Filter, Controller itself implements IActionFilter interface, so an OnActionExecuting method is available to be overridden within the controller class. This is another point where execution of any further action filters and the action itself can be cancelled by setting the result property to an ActionResult of your choice.
    • Action method itself is invoked with the parameters supplied by the model binder.
    • Action Filter – OnActionExecuted: After the execution of the action method, OnActionExecuted method on the action filter collection (including the OnActionExecuted method on the controller) is executed. In this method you can get information on any exceptions that were thrown during the action method execution via ActionExecutedContext.Exception. Here you have a chance to handle the exceptions and stop further propagation of the exception by using the ActionExecutedContext.ExceptionHandled property.
    • Exception Filter – OnException: An exception filter must implement IExceptionFilter interface. As with other types of filters, it can be applied as an attribute. The controller implements IExceptionFilter interface and provides access to its functionality via OnException method that can be overridden within the controller class. This is called if an exception is thrown anywhere during action or result execution. An exception thrown in the Action can be handled in OnActionExecuted to stop it from being propagated up to this stage. Similarly as will be explained later on, an exception thrown during result execution can be handled inside a ResultFilter OnResultExecuted stage to stop it from getting here. ExceptionFilter offers you the final chance to handle exceptions before the exception is thrown up to Global.asax. HandleErrorAttribute is an exception filter provided out of the box with the framework to help with exception handling within the controller.
    • Result Filter - OnResultExecuting: This step occurs before the ActionResult is executed. A result filter must implement IResultFilter interface and the Controller class offers an implementation via the OnResultExecuting and OnResultExecuted methods. The request will only get here if there are no unhandled exceptions in the action method and the OnActionExecuted stage.
    • ActionResult execution – This is the stage where the ActionResult is executed and the http response determined. ActionResult is just an abstract class and is extended by specific type of action results like ViewResult (for HTML output), JsonResult (For Json output), RedirectResult (an HTTP redirect), ContentResult (for text output) etc. This is another extensibility point, which allows a custom ActionResult implementation. See an example here: http://blog.maartenballiauw.be/post/2008/05/ASPNET-MVC-custom-ActionResult.aspx

IView and IViewEngine

    • Rendering a view – When the return type from the action is that of a ViewResult there are two interfaces, IView and IViewEngine that get involved. IViewEngine interface defines the contract for locating a view or a partial view. IView defines the contract for rendering the view. By default the framework uses WebFormView and WebFormViewEngine which process .aspx based views. A custom view processing infrastructure can be implemented by creating custom views/view engines. The MVCContrib project on codeplex provides several ViewEngines including those based on XSLT, Brail and nVelocity. Some more information on creating a custom ViewEngine can be found here: http://www.singingeels.com/Articles/Creating_a_Custom_View_Engine_in_ASPNET_MVC.aspx
    • Result Filter – OnResultExecuted: This is the last step executed within the controller and occurs after the result has been executed and http response produced. If any exceptions are thrown during the result execution, then you’ll have a chance to handle the exception here. If not the exception is bubbled up towards Exception Filters (see Exception Filters - OnException stage).

After this stage the http response would have been produced and the control is transferred back to HttpApplication to carry through the rest of the lifecycle. This concludes our journey through the request processing occurring within the ASP.NET MVC framework.

This follow-up post explained the passage of a request through the ASP.NET MVC framework and describes how the request is processed through the various stages within. Hopefully it gives a good idea of the ASP.NET MVC lifecycle and extensibility points within it.

Published Feb 11 2009, 07:41 AM by gopalk
Filed under: ,

Comments

 

multi-card keno games said:

This blog Is very informative , I am really pleased to post my comment on this blog . It helped me with ocean of knowledge so I really believe  you will do much better in the

future . Good job web master .

June 25, 2009 11:20 AM
 

Raj said:

Very well defined and explained. Thanks a lot.

October 17, 2009 2:48 AM
 

WebDevVote.com said:

You are voted!

Track back from WebDevVote.com

October 31, 2009 9:48 AM
 

DotNetShoutout said:

Thank you for submitting this cool story - Trackback from DotNetShoutout

January 13, 2010 8:45 PM
 

ASP.NET MVC: ?????? ???? ???????????????? | DevLanfear - .NET ???????????????????? said:

Pingback from  ASP.NET MVC: ?????? ???? ???????????????? | DevLanfear - .NET ????????????????????

January 15, 2010 9:15 PM
 

Lanfear said:

Very nice guide. We are looking forward for next chapters.

Thanks from .NET developer from Kiev.

January 15, 2010 9:16 PM
 

Comfly said:

Very good post. Thank you, author!

January 18, 2010 9:57 PM
 

Twitter Trackbacks for How does ASP.NET MVC work ??? Part 2 - gopalk [charteris.com] on Topsy.com said:

Pingback from  Twitter Trackbacks for                 How does ASP.NET MVC work ??? Part 2 - gopalk         [charteris.com]        on Topsy.com

February 9, 2010 3:56 PM
 

Mujahid said:

Nice article, good job.

February 23, 2010 10:40 AM
 

ASP MVC Pipeline - Andrew Berezovskiy // Django/ASP.NET MVC fan said:

Pingback from  ASP MVC Pipeline - Andrew Berezovskiy // Django/ASP.NET MVC fan

March 5, 2013 10:11 PM

Leave a Comment

(required) 
(optional)
(required) 
Submit
Powered by Community Server (Commercial Edition), by Telligent Systems