Question

I have gone though MVC Request life cycle and I still did not get any clarity in where the requests are routed to handlers based on registered routes.

We place MVC requests with an url it then finds the controller and delivers the right cshtml page. As the url is without any resource type, how http module events or http handlers differentiate MVC requests and passes it to the right controller.

Was it helpful?

Solution

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 the RouteCollectionExtensions 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 the MvcRouteHandler 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 the MvcHandler 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!

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top