Web API Series Tutorial 2.2-asp.net Routing and Action selection mechanism in the Web API

Source: Internet
Author: User

This article describes how the ASP. NET WEB API routes HTTP requests to specific actions on the controller.

Note: To learn about the high-level overview of routing, see the routing in ASP.

This article focuses on the details of the routing process. Hopefully this article will help if you create a Web API project and find that some requests are not routed as you expect.

There are three main stages of routing:

    1. To match a URI to a route template
    2. Select a controller
    3. Select an action

You can replace some of these processes with your own customary behavior. In this article, I'll describe the default behavior. At the end, I'll point out where you can customize the behavior.

Routing Template (route Templates)

A route template looks very similar to a URI path, but it can contain placeholders indicated by curly braces.

"api/{controller}/public/{category}/{id}"

When you create a route, you provide default values for some or all of the placeholders:

new"all" }

You can also provide some constraints (constraints) that limit how the URI field can match a placeholder:

constraintsnew { id = @"\d+" }   //if"id"isor more digits.

The framework tries to match the fields in the URI path to the template. The text in the template must match exactly. A placeholder can match multiple variables, unless you specify a constraint. The framework does not match other parts of the URI, such as host names or query parameters. The framework selects the first route only in the routing table used to match the URI.

There are two special placeholders: "{controller}" and "{action}".

    • "{Controller}" provides the name of the controller.
    • ' {action} ' provides the name of the action. In the Web API, "{action}" is ignored.
Defaults

If you provide the default API, the routes will match the URIs that are missing. For example:

routes.MapHttpRoute(    "DefaultApi",    "api/{controller}/{category}",    new"all" });

For URI http://localhost/api/products will match this route. The {category} field is assigned the default value of all.

Routing Dictionary (Route Dictionary)

If the framework finds a match for a URI, it creates a dictionary collection that contains the values that each placeholder applies to. The key is a placeholder name that does not contain curly braces. The value is extracted from the URI path or the default form. The dictionary is stored in the Ihttproutedata object.

During the route matching phase, the "{controller}" and "{action}" placeholders are treated like other placeholders. They are simply stored in the dictionary together with other values.

For defaults, it can have a special value of routeparameter.optional. If a placeholder is assigned to this value, then this value is not added to the routing dictionary. For example:

routes.MapHttpRoute(    "DefaultApi",    "api/{controller}/{category}/{id}",    "all", id = RouteParameter.Optional });

For the URI path "Api/products", the routing dictionary will contain:

    1. Controller: "Products"
    2. Category: "All"

For "api/products/toys/123", however, the routing dictionary will contain:

    1. Controller: "Products"
    2. Category: "All"
    3. ID: "123"

For defaults, it also contains a value that does not appear anywhere in the routing template. If the route matches, the value is stored in the dictionary. For example:

routes.MapHttpRoute(    "Root",    "api/root/{id}",    "customers", id = RouteParameter.Optional });

If the URI path is "Api/root/8", the dictionary will contain two values:

    • Controller: "Customers"
    • ID: "8"
Select Controllers (Selecting a controller)

The selection of the controller is handled by the Ihttpcontrollerselector.selectcontroller method. This method needs to pass in an Httprequestmessage instance and return the Httpcontrollerdescriptor object. The default implementation is implemented by the Defaulthttpcontrollerselector class. This class uses a simple algorithm:

    1. Look for the key "controller" in the routing dictionary.
    2. Extract the value of this key and add the string "controller" to get the type name of the controller
    3. Use this type name to find a Web API controller

For example, if the routing dictionary contains a key-value pair "Controller" = "Products", then the controller type is "ProductsController". If there is no matching type, or there are multiple matches, the framework sends an error to the client.

For step 3,defaulthttpcontrollerselector, the Ihttpcontrollertyperesolver interface is used to get a list of Web API controller types. The default implementation of Ihttpcontrollertyperesolver returns (a) implementation ihttpcontroller, (b) not abstract, (c) All public classes with names ending with "Controller".

Action Selection

After selecting the controller, the framework selects the action by calling the Ihttpactionselector.selectaction method. This method needs to pass in a httpcontrollercontext parameter and return a Httpactiondescriptor object.

The default implementation is provided by the Apicontrolleractionselector class. To select an action, it looks for the following requirements:
1) HTTP method of the request
2) "{action}" placeholder in the routing template (if present)
3) parameters of the action in the controller

Before we look at the selection algorithm, we need to understand something about the controller action.

what methods in the controller are considered to be "actions"? when an action is selected, the framework only looks for common instance methods in the controller. Of course, it excludes some "special" methods (constructors, events, manipulation overloads, etc.) and methods that inherit from the Apicontroller class.

http method. the framework selects only the actions of the HTTP method that matches the request, depending on the following points:

    1. You can use a property to specify the HTTP method: Acceptverbs,httpdelete,httpget,httphead,httpoptions,httppatch,httppost or Httpput.
    2. Alternatively, if the name of a controller method starts with "Get", "Post", "Put", "Delete", "Head", "Options" or "Patch", then the HTTP method is supported as agreed.
    3. If the above points are not included, the method that supports post.

parameter bindings. parameter binding refers to how the Web API creates a value for a parameter. Here is the default rule for parameter binding:

    1. Simple types are extracted directly from the URI
    2. Complex types from Request for weight extraction

Simple types include all. NET Framework basic type (. NET Framework primitive types), plus datetime, Decimal, Guid, String, and TimeSpan. For each action, there is at most one parameter that can read the request body.

Note: It is also possible to overload the default binding rules. View Webapi Parameter binding under the hood.

With these background knowledge, here is the algorithm for motion selection:

    1. Creates an action list based on the controller that the HTTP request method matches to.
    2. The Action routing dictionary contains an "action" record, removing the action whose name does not match the value.
    3. Try to match the action parameters to the URI according to the following rules:

      • A For each action, a simple Type argument list is obtained when the binding obtains the argument from the URI. Executes an optional parameter.
      • b from this list, either in the routing dictionary or in the URI query string, try to find a match for each parameter name. The match is case insensitive and does not depend on the parameter order.
      • c when each parameter in the list has a match in the URI, select an action.
      • D If multiple actions meet these criteria, select one with the most parameters to match.
    4. Actions that contain the [Nonaction] property are ignored.

Step 3 is probably the easiest to confuse. The basic idea is that the parameter can get its value from the URI, the request body, or the binding. For parameters from URIs, we make sure that the URI does contain a value for the parameter, either in the path (through the routing dictionary) or in the query string.

For example, consider the following action:

publicvoidGet(int id)

This ID parameter is bound to the URI, so this action can be matched to a URI that contains a value for "id", whether in the routing dictionary or in the query string.

Optional parameters are an exception because they are optional. For optional parameters, it doesn't matter if the binding does not get this value from the URI.

Complex types are an exception for a number of different reasons. A complex type can only be bound to a URI by a custom binding. However, in this case, the framework cannot know beforehand that the parameter may be bound to a special URI. To figure it out, you need to execute the binding. The goal of this selection algorithm is to select an action from the static description before executing any bindings. Therefore, complex types are executed from this matching algorithm.

When the action is selected, all parameter bindings are executed.

Summarize:

    1. The action must match the requested HTTP method.
    2. The action name (if present) must match the "action" entry in the routing dictionary
    3. For all parameters of an action, if the parameter is extracted from the URI, the parameter name must be found in the routing dictionary or URI query string. (except for parameters that are optional and complex types.) )
    4. Try to match the maximum number of parameters. But the best match can also be a method that does not contain any parameters.
Extended sample (Extended Example)

Routing:

routes.MapHttpRoute(    "ApiRoot",    "api/root/{id}",    "products", id = RouteParameter.Optional });routes.MapHttpRoute(    "DefaultApi",    "api/{controller}/{id}",    defaults: new { id = RouteParameter.Optional });

Controller:

 Public classproductscontroller:apicontroller{ PublicIenumerable<product>GetAll() {} PublicProductGetById(intIdDoubleVersion =1.0) {} [HttpGet] Public void Findproductsbyname(stringName) {} Public void Post(Productvalue) {} Public void Put(intID, Productvalue) {}}

HTTP request:

GEThttp://localhost:34701/api/products/1?version=1.5&details=1
Route matching (Route Matching)

The URI is matched to a route named "Defaultapi". This routing dictionary contains the following terms:

    • Controller: "Products"
    • ID: "1"

This routing dictionary does not contain the query string "version" and "Details", but these are still considered when the action is selected.

controller selection (controllers Selection)

The controller type is ProductsController, depending on the "controller" entry in the routing dictionary.

Action Selection (action Selection)

The HTTP request is a GET request. The corresponding controller actions that support get are getall, GetByID, and Findproductsbyname. The routing dictionary does not contain any "action" entries, so we do not need to match the action name.

Next, we try to match the parameter name of the action and now only find it in the get action.

Action Parameters to Match
GetAll None
GetById "id"
Findproductsbyname "Name"

Note that the version parameter of GetByID is not considered because it is an optional parameter.

It is obvious that the GetAll method can match, and the GetByID method can match, because the routing dictionary contains "id". The Findproductsbyname method does not match.

Finally, the GetByID method wins because it can match to a parameter, which corresponds to no parameter matching getall. This method is followed by the values of the following parameters:

    • ID = 1
    • Version = 1.5

Note that although the version parameter is not used in the selection algorithm, the value of the parameter is still in the query string from the URI.

extension Point (Extension Points)

The Web API provides extensibility points for some parts of the routing process.

Interface Description
Ihttpcontrollerselector Selects the controller.
Ihttpcontrollertyperesolver Gets the list of controller types. The Defaulthttpcontrollerselector chooses the controller type from this list.
Iassembliesresolver Gets the list of project assemblies. The ihttpcontrollertyperesolverinterface uses this list to find the controller types.
Ihttpcontrolleractivator Creates new controller instances.
Ihttpactionselector Selects the action.
Ihttpactioninvoker invokes the action.

To provide your own implementation for any of these interfaces, use the Services collection on the Httpconfiguration object:

var config = GlobalConfiguration.Configuration;config.Services.Replace(typeofnew MyControllerSelector(config));

Web API Series Tutorial 2.2-asp.net Routing and Action selection mechanism in the Web API

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.