Asp. Net Web API (III), asp. netwebapi
Routing Tables route table
In Asp. Net Web API, a controller is a class for processing HTTP requests. The public method of the controller is called action method or simple Action. When a Web API receives a request, it routes the request to an Action.
Note: Web API routing is very similar to Asp. Net MVC routing. The main difference is that the Web API uses the HTTP method instead of the URI path to select Action.
To determine which Action is called, this framework uses a registry. The project template of Visual Studio Web API creates a default route:
1 config.Routes.MapHttpRoute(2 name: "DefaultApi",3 routeTemplate: "api/{controller}/{id}",4 defaults: new { id = RouteParameter.Optional }5 );
This route is defined in the WebApiConfig file, which is located in the App_Start directory.
When the Web API framework receives an HTTP request, it tries to match its URI based on a routing template in the route table. If no route match exists, the client will receive a 404 (not found) error. For example, the following URI matches the default route
- /Api/product
- /Api/product/1
- /Api/product? Category = category
However, the following URI does not match because it lacks the "api" field.
Note: The reason why "api" is used in routing is to avoid routing conflicts with ASP. net mvc. In this way, you can use "/product" to enter a controller, and "/api/product" to enter a Web API controller. If you do not like this Convention, you can modify the default route table.
Once a matched route is found, the Web API selects the corresponding Controller and Action.
1. To locate the Controller, Web API adds "Controller" to the value of {Controller} variable.
2. To find the Action, the Web API searches for the HTTP method and then finds a method whose name starts with the HTTP method name. For example, for a Get request, the Web API looks for .. "Action at the beginning. This Convention applies only to GET, POST, PUT, and DELETE methods. By using attribute on the Controller, you can start other HTTP methods.
3. Other placeholder variables in the routing template. For example, {id} will be mapped to the Action parameter.
Routing Variations route change HTTP Method
Instead of using the naming convention of the HTTP method, you can specify the HTTP Method for an Action, and use the HttpGet, HttpPost, HttpPut, or HttpDelete attribute to cultivate the morality of the Action method.
In the following example, the FindProduct method is mapped to the GET request.
1 [HttpGet]2 public Product FindProduct(int id)3 {4 return repository.Get(id);5 }
When using the above Code, you must first comment on the GetProduct (int id) written above );
Because if you do not comment on the Web API, multiple operation errors that match the request are returned.
A Web API allows an Action to correspond to multiple HTTP methods;
1 [AcceptVerbs("GET","POST","HEAD")] 2 public Product FindProduct(int id) 3 { 4 return repository.Get(id); 5 } 6 [AcceptVerbs("MKCOL")] 7 public void MakeCollection() 8 { 9 10 }
Method 1: indicates that the Action receives the http get, POST, and HEAD methods.
Method 2: WebDAV (HTTP Method Based on Distributed Web books and Version Control) is an extended HTTP method. MKCOL is a method of WebDAV, it creates a set at the position specified by URI)
Route by Action name
In the default routing template, this Web API uses the HTTP method to select Action. However, you can also create a route entry containing the Action name in the URI.
1 config.Routes.MapHttpRoute(2 name: "DefaultApi",3 routeTemplate: "api/{controller}/{Action}/{id}",4 defaults: new { id = RouteParameter.Optional }5 );
In this routing template, the {action} parameter is named the Controller's Action method. To use this style, you need to use annotation attributes to specify the allowed HTTP methods. For example, assume that your controller already has the following methods:
1 [HttpGet] 2 public string Details(int id);
In this case, a GET request "api/Product/Details/1" will be mapped to this Detail method. This type of routing is similar to Asp. Net MVC, and may be similar to RPC APIs.
You can also overwrite the action name by using the ActionName annotation attribute. In the following example, two actions are mapped to "api/product/thumbnail/id ". One supports GET and one supports POST.
1 [HttpGet]2 [ActionName("Thumbnail")]3 public HttpResponseMessage GetThumbnailImage(int id);4 [HttpPost]5 [ActionName("Thumbnail")]6 public void AddThumbnailImage(int id);
NonActions
To prevent a method from being requested as an Action, you can use the NonAction annotation attribute. It sends a signal to the framework: This method is not an Action, even if it may match the routing rule
1 [NonAction]2 public void IsNoAction();
Route Templates
The routing template looks like a URI path, but it can have placeholders and use {} to indicate:
"api/{controller}/public/{category}/{id}"
When creating a route, you can provide default values for some or all placeholders.
defaults: new { category = "all" }
You can provide constraints to restrict how URI fragments match placeholders.
Constraints: new {id = @ "\ d +"} // match only when "id" is one or more numbers
The preceding statement limits the value of a segment through a regular expression. The preceding comment indicates that the id segment matches only one or more numbers, therefore, the id segment in the URI must be a number to match the route.
This framework tries to match the fragments in the URI path with this template. The text in the template must be strictly matched. A placeholder can match any value unless you specify a constraint. This framework does not include other parts of the URI, such as the host name or a query string. This framework selects the first matched route in the routing table.
There are two special placeholders: "{Controller}" and "{Action }".
{Controller} provides the Controller name
{Action} provides the Action name. In Web APIs, the Common Convention ignores {Action.
Defaults (default)
If you provide the default value, the route matches the URI of these fragments. For example
1 routes.MapHttpRoute(2 name: "DefaultApi", 3 routeTemplate: "api/{controller}/{category}", 4 defaults: new { category = "all" } 5 );
This URI "http: // localhost/api/products" matches this route. The "{category}" segment will be assigned the default value "all ".
Route Dictionary (Route field)
If this framework finds a matched URI, it creates a dictionary containing each placeholder value. This key value is a placeholder name. This value is taken from the URI path or default value. This field is included in the IHttpRouteData object. In the routing matching stage, the processing of the special {Controller} and {Action} placeholders is the same as that of other placeholders. They are simply stored in the dictionary with other values.
Special RouteParameter. Optional values can be used in the default value. If a placeholder is assigned with this value, this value will not be added to the dictionary, for example
1 routes.MapHttpRoute( 2 name: "DefaultApi", 3 routeTemplate: "api/{controller}/{category}/{id}", 4 defaults: new { category = "all", id = RouteParameter.Optional } 5 );
For the URI path "api/product", the routing dictionary will contain: controller: "product", category: "all"
However, for "api/product/toys/123", the routing dictionary will contain: controller: "product", category: "toys"
This default value can also contain values in the unused routing template. If this route matches, the value is stored in the routing dictionary. For example
1 routes.MapHttpRoute( 2 name: "Root", 3 routeTemplate: "api/root/{id}", 4 defaults: new { controller = "product", id = RouteParameter.Optional } 5 );
If the URI path is "api/root/7", the dictionary contains two values: controller: "product", id: "8 ".
Selecting a Controller
The Controller is selectedIHttpControllerSelector. SelectControllerMethod. This method usesHttpRequestMessageThe instance is a parameter. And returnHttpControllerDescriptor.
The default implementation is provided by the DefaultHttpControllerSelector class. This class uses a very direct algorithm:
1. Find the "controller" Key of the route dictionary.
2. Obtain the value of this key and append the string "Controller" to obtain the type name of the Controller.
3. Search for the Web API controller with this type name
For example, if the key-value pair of the route dictionary is "controller" = "product", the controller type is "ProductController". If no match exists or multiple matches exist, the Web API framework returns an error to the client.
For step 3,DefaultHttpControllerSelectorUseIHttpControllerTypeResolverInterface to obtain a list of Web API control types.IHttpControllerTypeResolverBy default, all public classes that meet the following conditions are returned:
Action Selection
After the controller is selected, the Web API framework selects Action by calling the IHttpActionSelector. SelectAction method. This method takes HttpControllerContext as the parameter and returns HttpActionDescriptor.
By defaultApiControllerActionSelectorClass. To select an Action, you can find the following:
Before searching and selecting an algorithm, we need to understand the Controller Action.
Which methods of the controller are viewed as actions?When selecting an Action, this framework only examines the public instance method of the controller. Besides, it will exclude methods with special names (constructors, events, operators, reloads, etc.) and Class Methods integrated from ApiController.
HTTP Methods
The Web API framework selects only the Action that matches the HTTP Method of the request.
Parameter Bindings
Parameter binding refers to how a Web API creates a parameter value. The following are the default rules for parameter binding:
1. Simple type is taken from URI
2. complex types are taken from the request body
Simple types include all ". NET Framework simple types", and DateTime, Decimal, Guid, String, and TimeSpan. For each Action, only one parameter can read the Request body.
In this context, the Action selection algorithm is as follows:
A: For each Action, obtain the simple parameter list, which is the place where the URI parameter is bound. This list does not contain optional parameters
B: From this list, try to find the matching of each parameter in the routing dictionary or URI query string. Matching is case-insensitive and irrelevant to the order of parameters.
C: select such an Action. Each parameter in the list has a match in the URI.
D: if more than one Action meets these conditions, select the one with the most matching parameters.
4. Ignore the Action marked with the [NonAction] annotation attribute.
Step 2 may cause rang problems. The basic idea is that you can get the parameter value from URI, request body, or a custom binding. For parameters from the URI, we want to ensure that the URI actually contains a value for this parameter in its path (through the routing dictionary) or query string.
For example, consider the following actions
public void Get(int id)
Its id is bound to the URI. Therefore, this Action can only match the URI that contains the id value in the routing dictionary or query string.
Optional parameters are an exception because they are optional. For optional parameters, it does not matter if the binding cannot obtain its value through URI.
Complex types are an exception for another reason. A complex type can only be bound to a URI through custom binding. However, in this case, the Web API framework cannot know in advance whether this parameter is bound to a special URI. To identify the situation, this framework needs to call this binding. The algorithm is used to select an Action based on the static description before binding is called. Therefore, the owner type is out of the matching algorithm.
After the Action is selected, All Parameter Bindings are called.
Summary:
Extended Points
Web APIs Provide extensions for some parts of the routing process.
To provide your own implementation for any of the above interfaces, you can use the Services set of the HttpConfiguration object:
var config = GlobalConfiguration.Configuration;config.Services.Replace(typeof(IHttpControllerSelector), new MyControllerSelector(config));