In the previous article, we introduced filters. Through methods and result filters, we can inject our own functions before and after MVC execution methods and results. Through authorization filters, we can perform some permission checks, prevents unauthorized users from calling methods and exceptions generated during method execution through exception filters. Before executing the method, how does MVC determine which controller to use and its method?
As we know, MVC uses the defaultcontrollerfactory controller factory to instantiate the controller. The general process is as follows:
1. By default, the getroutedata method of the route class will parse the URL of the current request according to the URL rule we set, and save the parameters in the URL rule to the routedata. values collection. We know that MVC adds a default route item:
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
According to the above rules, if the request URL is:
Http: // localhost/news/getnewslist
Then the corresponding routedata. Values ["controller"] = "news"; routedata. Values ["action"] = "newslist"
2. defaultcontrollerfactory determines the actual controller type based on route. Values ["controller"] And instantiates it. The controller factory in the preceding example knows that the controller type to be instantiated is newscontroller.
3. Through the execute method of the controller object returned by the Controller factory, the controller uses routedata through a class that implements the iactioninvoker interface (the default is the controlleractioninvoker class. values ["action"] value to determine the method in the specific Running Controller.
4. Execute the method in the Controller to generate actionresult
5. Execute actionresult. executeactionresult to generate the final response content.
Steps 4 and 5 involve the filters described in the previous chapter, and the method selector is used in step 3rd, in the controlleractioninvoker class, the actionmethodselector class is used to obtain the method that matches the route information. The specific execution process is shown in:
The red endpoint in the figure indicates an exception. Actionmethodselector first obtains method names that are equal to routedata from non-static methods in the controller. values ["action"] or the name specified by the actionname attribute is routedata. values ["action"] method list, and then calls the selector on each method in the method list in turn, removing the part returned by the selector as false, if a method is used for matching, this method is used. If there is no method for matching, check that there is no selector in the method list. If there is one, select it. If not, directly call the handleunknownaction method of the controller. In the controller, this method returns an HTTP Error 404 by default.
The default selector type implemented in MVC is as follows:
Actionnameattribute is used to declare the alias of a method. Generally, actionname is used to map different methods in the Controller to the same Controller method (access different methods with the same URL ). It inherits from the abstract class actionnameselectorattribute. You can also inherit from this class to implement your own actionname feature (though it seems useless ).
The actionmethodselectorattribute abstract class is the base class of some column selectors. when selecting an actionmethodselector method, the isvalidforrequest method is called to check whether the current method is valid. MVC implements several default selectors: httpget, httppost, httpdelete, httpput, and acceptverbs used to check the current request method (matching the get method and post method, and acceptverbs used to match multiple methods ), in fact, selectors such as httpget are encapsulation of acceptverbs. Another selector: nonaction indicates that the current method is not exposed to external requests (its isvalidforrequest always returns false ). If we need to implement our selection logic, we should inherit from the actionmethodselectorattribute class.
The following example uses a selector to map the same URL to different controller methods based on the browser type:
1. Create an empty MVC Project
2. Implement browseselectorattribute
Show row number copy code? Browseselectorattribute
public class BrowseSelectorAttribute : ActionMethodSelectorAttribute
{
private string _userAgent = String.Empty;
public BrowseSelectorAttribute(string userAgent)
{
_userAgent = userAgent;
}
public override bool IsValidForRequest(ControllerContext controllerContext, System.Reflection.MethodInfo methodInfo)
{
return controllerContext.HttpContext.Request.UserAgent.Contains(_userAgent);
}
}
3. Create a homecontroller Controller
Show row number copy code? Homecontroller
public class HomeController : Controller
{
[ActionName("Index")]
[BrowseSelector("MSIE")]
public ActionResult IEIndex()
{
Return content ("access via IE browser ");
}
[ActionName("Index")]
[BrowseSelector("Chrome")]
public ActionResult ChromeIndex()
{
Return content ("access via Chrome ");
}
[ActionName("Index")]
public ActionResult OtherIndex()
{
Return content ("access via other browsers ");
}
}
Finally, the selector function seems to be similar to the authorization filter: both can "filter" the Controller method, but they are essentially different: When the authorization filter is executed, MVC has determined which Controller Method to call, the selector is a set of filtering conditions when the Controller method is selected by MVC. If no matching method exists after filtering by selector, the system will Return Error 404 by default. If a method is terminated by the authorization filter, the result you specified in the context parameter of the authorization filter will be returned.
Source code download