You have this document from Microsoft´s ASP .Net site, describing in detail the MVC 5 request lifecycle and how it IS integrated into the ASP .Net lifecycle. Some sections of the diagrams in the pdf itself link to relevant pages in the msdn.
Another good resource are this set of slides from Lukasz Lysic that explains in detail the request lifecycle in MVC 4.
EDIT: I am not a fan of link-only answers, so I have added some more detail below.
On your machine level web.config, you will see the UrlRoutingModule
registered as an IHttpModule
. For example, on my computer I have:
<system.web>
<httpModules>
...
<add name="UrlRoutingModule-4.0" type="System.Web.Routing.UrlRoutingModule" />
...
</httpModules>
<system.web>
On the PostResolveRequestCache
application event, the routing module iterates through all the routes in the RouteCollection
property and searches for a route that has a URL pattern that matches the format of the HTTP request. When the module finds a matching route, it retrieves the IRouteHandler
object for that route. From the route handler, the module gets an IHttpHandler
object and uses that as the HTTP handler for the current request (calling its ProcessRequest
method or its async counterparts BeginProcessRequest
and EndProcessRequest
).
- You can check the UrlRoutingModule code here on the Microsoft .Net Reference Source site.
In the case of an MVC application, when you add a route in global.asax
using the MapRoute
extension method, an MVCRouteHandler
is created.
Check the
MapRoute
method in theRouteCollectionExtensions
class:public static Route MapRoute(this RouteCollection routes, string name, string url, object defaults, object constraints, string[] namespaces) { if (routes == null) { throw new ArgumentNullException("routes"); } if (url == null) { throw new ArgumentNullException("url"); } Route route = new Route(url, new MvcRouteHandler()) { Defaults = CreateRouteValueDictionaryUncached(defaults), Constraints = CreateRouteValueDictionaryUncached(constraints), DataTokens = new RouteValueDictionary() }; ConstraintValidation.Validate(route); if ((namespaces != null) && (namespaces.Length > 0)) { route.DataTokens[RouteDataTokenKeys.Namespaces] = namespaces; } routes.Add(name, route); return route; }
So when a request is matched to an MVC route, it will be handled by an MvcRouteHandler
. As mentioned above, the purpose of the IRouteHandler
of a route is to get an IHttpHandler
that will be used by the application to continue handling the request. The MvcRouteHandler
will return an MvcHandler
which is the entry point of the MVC-specific pipeline.
Check the
GetHttpHandler
method of theMvcRouteHandler
class:protected virtual IHttpHandler GetHttpHandler(RequestContext requestContext) { requestContext.HttpContext.SetSessionStateBehavior(GetSessionStateBehavior(requestContext)); return new MvcHandler(requestContext); }
The MVC-specific pipeline basically starts with the ProcessRequest
method (Or the async BeginProcessRequest
/EndProcessRequest
). The MvcHandler
will get the IControllerFactory
(By default, DefaultControllerFactory
will be used, unless you register your own using ControllerBuilder.Current.SetDefaultControllerFactory
in global.asax Application_Start), use it to create the controller instance based on the current route values and start controller execution.
Check the
ProcessRequest
method of theMvcHandler
class:protected internal virtual void ProcessRequest(HttpContextBase httpContext) { IController controller; IControllerFactory factory; ProcessRequestInit(httpContext, out controller, out factory); try { controller.Execute(RequestContext); } finally { factory.ReleaseController(controller); } } private void ProcessRequestInit(HttpContextBase httpContext, out IController controller, out IControllerFactory factory) { // If request validation has already been enabled, make it lazy. This allows attributes like [HttpPost] (which looks // at Request.Form) to work correctly without triggering full validation. // Tolerate null HttpContext for testing. HttpContext currentContext = HttpContext.Current; if (currentContext != null) { bool? isRequestValidationEnabled = ValidationUtility.IsValidationEnabled(currentContext); if (isRequestValidationEnabled == true) { ValidationUtility.EnableDynamicValidation(currentContext); } } AddVersionHeader(httpContext); RemoveOptionalRoutingParameters(); // Get the controller type string controllerName = RequestContext.RouteData.GetRequiredString("controller"); // Instantiate the controller and call Execute factory = ControllerBuilder.GetControllerFactory(); controller = factory.CreateController(RequestContext, controllerName); if (controller == null) { throw new InvalidOperationException( String.Format( CultureInfo.CurrentCulture, MvcResources.ControllerBuilder_FactoryReturnedNull, factory.GetType(), controllerName)); } }
This should explain how incoming requests are matched to controllers in MVC. For the rest of the MVC pipeline, please check the links at the beggining of the post!