Previous MVC event series (9): How does MVC take over requests in Pipeline?

Source: Internet
Author: User

Article content

As mentioned in the previous chapter, you can dynamically Add a Route method before the HttpModules initialization to customize your HttpHandler and finally take over the request. Is MVC implemented in this way? In this chapter, we will analyze the relevant MVC source code to verify our problem.

Create an MVC3 Web Application first, and select the default template to include HomeController and AccountController by default after creation. We know that MVC must take over the request before it can be processed through these controllers. Then we should go to Global first. asax. check the code in the cs file (define the request to take over before initializing the HttpModule, so you can only come here to find the code (or dynamically add it using features such as WebActivator), Global. asax. there are few codes in the cs file, but there is something we need. First, we found a line of code in the Application_Start method:

RegisterRoutes(RouteTable.Routes);

In this line of code, we can see that the called method name RegisterRoutes indicates registering a Route. But why is the parameter a global RouteTable. Routes set? Find the RegisterRoutes method to see the specific content:

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    );}

This method has two lines of code. The first line is to ignore a Route (we will not look at this first), and the second line is to register a new Route using the MapRoute method, by default, it is mapped to the Index Action of the Home Controller. We may have thought of RouteCollection (that is, the imported RouteTable. the MapRoute method of Routes) is to provide the entrance to take over the request, but how can we pass the MVC HttpHandler into it? Go to this MapRoute method (you need to install ReShaper to find the source code of MVC) and adjust it to the RouteCollectionExtensions class of MVC. It is found that MapRoute is not the built-in method of RouteCollection, but an extension method provided in the MVC Source Code. The Code is as follows:

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 = new RouteValueDictionary(defaults),        Constraints = new RouteValueDictionary(constraints),        DataTokens = new RouteValueDictionary()    };    if ((namespaces != null) && (namespaces.Length > 0))    {        route.DataTokens["Namespaces"] = namespaces;    }    routes.Add(name, route);    return route;}

The main function of this Code is to create a new Route, and then add the Route to the static set RouteTable we just mentioned. in Routes for later use when looking for Handler, OK, this step conforms to the analysis in the previous chapter.

Next, let's take a look at how Route is new. The parameters in the Code are imported into the url we know and an MVCRouteHandler instance. This step also conforms to our previous analysis, let's take a look at how the GetHttpHandler method of MVCRouteHandler is implemented to obtain MVCHandler:

    public class MvcRouteHandler : IRouteHandler {         private IControllerFactory _controllerFactory;         public MvcRouteHandler() {         }         public MvcRouteHandler(IControllerFactory controllerFactory) {            _controllerFactory = controllerFactory;        }         protected virtual IHttpHandler GetHttpHandler(RequestContext requestContext) {            requestContext.HttpContext.SetSessionStateBehavior(GetSessionStateBehavior(requestContext));             return new MvcHandler(requestContext);         }         protected virtual SessionStateBehavior GetSessionStateBehavior(RequestContext requestContext) {            string controllerName = (string)requestContext.RouteData.Values["controller"];            IControllerFactory controllerFactory = _controllerFactory ?? ControllerBuilder.Current.GetControllerFactory();            return controllerFactory.GetControllerSessionBehavior(requestContext, controllerName);         }         #region IRouteHandler Members         IHttpHandler IRouteHandler.GetHttpHandler(RequestContext requestContext) {            return GetHttpHandler(requestContext);         }        #endregion    }

Looking at the above bold code, MvcRouteHandler implements the IRouteHandler's GetHttpHandler. This method calls the GetHttpHandler virtual method defined by MvcRouteHandler, in this virtual method, we can see a very important and long-awaited code -- return the MvcHandler instance. Let's take a look at the MvcHandler class and get it as we guess: inherited from a class of the IHttpHandler interface and also inherited from the IHttpAsyncHandler interface, we do not care how MvcHandler is implemented, but all the analysis in the previous sections has finally been verified, that is to say, the special processing Handler of Mvc is obtained here, and then the BeginProcessRequest method is called to access the Pipeline of Mvc for processing.

 

At this point, we finally figured out that Mvc is in the entire ASP. NET Runtime is how to take over the request, it should also be clear about the entire ASP. NET Runtime running mechanism. As for the Implementation Method of MvcHandler, we will analyze each line of code in many subsequent chapters. Today we have a small task, that is: after reading the implementation mechanism of Mvc, can we write a custom HttpHandler and dynamically register it through Route to implement our own custom extension? Let's try it.

Step 1: Create the HttpHandler class

Public class TomHandler: IHttpHandler {public TomHandler (RequestContext requestContext) {// do nothing} public virtual void ProcessRequest (HttpContext context) {string url = context. request. url. absoluteUri; context. response. write ("Current address:" + url); context. response. end (); // here we do nothing, only output URL address} public virtual bool IsReusable {get {return false ;}}}

Step 2: Create a RouteHandler class

public class TomRouteHandler : IRouteHandler{    IHttpHandler IRouteHandler.GetHttpHandler(RequestContext requestContext)    {        return new TomHandler(requestContext);    }}

In the GetHttpHandler implementation, return the TomHandler instance we defined.

 

Step 3: register our Route and RouteHandler

protected void Application_Start(object sender, EventArgs e){    Route route = new Route("tom/{other}", new TomRouteHandler());    RouteTable.Routes.Add(route);}

 

The URL is displayed when you access any file or subdirectory In the tom folder. The following is my test result:

Access: Http // localhost/tom/

Result: The expected result is not displayed (because it does not comply with our rules)

Access: Http // localhost/tom/123/

Result: The output is normal (indicating that TomHandler has taken over the request)

Access: Http // localhost/tom/123. aspx? Id = 123

Result: The output is normal (it also indicates that TomHandler has taken over the request)

 

Create a real tom folder, create an index.html file (content: 123) in it, and then access Http // localhost/tom/index.html. The rule conforms to our Route definition, however, the output result is not the expected result, but 123. Why? Remember the RouteCollection GetRouteData method mentioned in the previous chapter? Why is the explain path not the reason we expect the results ?.

 

Note: If you create an index. aspx file, and in index. aspx. write Response in the cs file. if the Write code outputs 123, the file will be executed according to the normal cycle of the aspx page (that is, the output 123 string. the httpHandlers node in web> uses the remove command *. if the aspx matching settings are removed, only the index is output. the string in the aspx file (including any Embedded C # code ).

 

Finally, we have learned how MvcHandler takes over the request, and I have made a simple example to verify this mechanism. Review the previous articles and we should have a general understanding of ASP. NET RunTime, Pipeline, and ASP. net mvc.

Synchronization and recommendation

This article has been synchronized to the Directory Index: the previous MVC Series

The previous MVC series of articles, including original articles, translations, reposts, and other types of articles. If they are useful to you, we recommend that you support them to give uncle the motivation to write.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.