In this article, I am going to discuss Routing and Action Selection in Web API i.e. how the ASP.NET Web API Framework routes or transfer an incoming HTTP request to a particular action method of a controller. Please read Routing in WEB API and ASP.NET WEB API Routing Variations articles before proceeding to this article where we discussed the High-Level Overview of Routing in ASP.NET WEB API.
The Routing module has three main phases:
A route template in WEB API looks very much similar to a URI path, but it can have placeholder values that are indicated with curly braces as shown in the below image.
When we create a route, it is also possible to provide default values for some or all of the placeholders as shown in the below image.
We can also provide some constraints which will restrict how a URI segment can match a placeholder as shown below.
The WEB API Framework tries to match the segments in the URI path with the route template present in the Route table. The Literals in the template must match exactly. A placeholder matches any value unless we specify some constraints. The WEB API framework does not match other parts of the URI such as the hostname or the query parameters. The framework always selects the first route in the routing table that matches the URI.
There are two special placeholders used in WEB API such as “{controller}” and “{action}”.
If you provide a default value for a placeholder, then the route will match a URI that is missing those segments. For example:
The URI “http://localhost/api/student/public” matches this route. The “{category}” segment is assigned the default value “all”.
Route Dictionary
When the WEB API Framework finds a match for a URI, then it creates a dictionary that will contain the value for each placeholder. As we know the dictionary contains the data in the form of a key-value pair. Here, the keys are nothing but the placeholder names but excluding the curly braces and the values are taken from the URI path or from the defaults. The dictionary is stored in the IHttpRouteData object as shown below.
During the route-matching phase, the special placeholders such as “{controller}” and “{action}” are treated just like any other placeholders. They are simply stored in the dictionary with the other values.
A default can have a special value RouteParameter.Optional. If a placeholder assigned with this value, then the value will not be added to the route dictionary. For example:
For the URI path “api/student/public“, the route dictionary will contain two elements such as:
If the URI path is “api/root/101“, then the dictionary will contain two elements such as:
The Controller selection in WEB API is handled by the IHttpControllerSelector.SelectController method.
As shown in the above image the SelectController method takes an HttpRequestMessage instance as a parameter and returns an HttpControllerDescriptor. The default implementation for the above SelectController method is provided by the DefaultHttpControllerSelector class as shown in the below image.
The above class uses a straightforward algorithm to find the controller as:
Action Selection
After selecting the controller, next, the WEB API Framework selects the action by calling the IHttpActionSelector.SelectAction method. This method takes an HttpControllerContext as a parameter and returns an HttpActionDescriptor as shown in the below image.
The default implementation for the SelectAction is provided by the ApiControllerActionSelector class as shown in the below image.
To select an action, it looks at the following algorithm:
When selecting an action, the WEB API Framework only looks at the public methods of the controller excluding the constructors, events, operator overloads, and so forth, and methods that are inherited from the ApiController class.
HTTP Methods:
The WEB API Framework only chooses the action methods that match the HTTP method of the incoming request, determined as follows:
The parameter binding is how Web API creates value for a parameter. Here is the default rule for parameter binding:
With that background, let see the action selection algorithm.
Example:
Let us consider the above points with an example.
Routes:
Controller:
HTTP request:
GET http://localhost:50470/api/student/1?version=2.1&details=1
Route Matching
The above URI matches the route named “DefaultApi”. The route dictionary contains the following elements:
Controller Selection
From the “controller” entry in the route dictionary, the WEB API Framework select the controller type is StudentController.
Action Selection
The above HTTP request is a GET request. The controller actions that support GET Request are GetAllStudents, GetStudentById, and FindStudentsByName. The route dictionary does not contain an entry for “action”, so we don’t need to match the action name.
Next, we need to match the parameter names for the actions, looking only at the GET actions.
Notice that the version parameter of GetStudentById is not considered, because it is an optional parameter.
The GetAllStudents method matches trivially. The GetStudentById method also matches, because the route dictionary contains the “id”. The FindStudentsByName method does not match.
The GetStudentById method wins because it matches one parameter, versus no parameters for GetAllStudents. The method is invoked with the following parameter values:
Summary:
I Hope this post will be helpful to understand the concept of Routing and Action Selection in Web API
Please share this post with your friends and colleagues.
For any queries please post a comment below.
Happy Coding 😉
The Routing module has three main phases:
- Matching the URI to a route template.
- Selecting a controller.
- Selecting an action.
A route template in WEB API looks very much similar to a URI path, but it can have placeholder values that are indicated with curly braces as shown in the below image.
When we create a route, it is also possible to provide default values for some or all of the placeholders as shown in the below image.
We can also provide some constraints which will restrict how a URI segment can match a placeholder as shown below.
The WEB API Framework tries to match the segments in the URI path with the route template present in the Route table. The Literals in the template must match exactly. A placeholder matches any value unless we specify some constraints. The WEB API framework does not match other parts of the URI such as the hostname or the query parameters. The framework always selects the first route in the routing table that matches the URI.
There are two special placeholders used in WEB API such as “{controller}” and “{action}”.
- The “{controller}” placeholder provides the name of the controller.
- Similarly, the “{action}” placeholder provides the name of the action. In Web API, the usual convention is to omit the “{action}” placeholder. That’s why when you create a new WEB API application, and then you can see that the default route template created by the framework does not include the action placeholder.
If you provide a default value for a placeholder, then the route will match a URI that is missing those segments. For example:
The URI “http://localhost/api/student/public” matches this route. The “{category}” segment is assigned the default value “all”.
Route Dictionary
When the WEB API Framework finds a match for a URI, then it creates a dictionary that will contain the value for each placeholder. As we know the dictionary contains the data in the form of a key-value pair. Here, the keys are nothing but the placeholder names but excluding the curly braces and the values are taken from the URI path or from the defaults. The dictionary is stored in the IHttpRouteData object as shown below.
During the route-matching phase, the special placeholders such as “{controller}” and “{action}” are treated just like any other placeholders. They are simply stored in the dictionary with the other values.
A default can have a special value RouteParameter.Optional. If a placeholder assigned with this value, then the value will not be added to the route dictionary. For example:
For the URI path “api/student/public“, the route dictionary will contain two elements such as:
- controller: “student”
- category: “all”
- controller: “student”
- category: “cse”
- id: “101”
If the URI path is “api/root/101“, then the dictionary will contain two elements such as:
- controller: “Employee”
- id: “101”
The Controller selection in WEB API is handled by the IHttpControllerSelector.SelectController method.
As shown in the above image the SelectController method takes an HttpRequestMessage instance as a parameter and returns an HttpControllerDescriptor. The default implementation for the above SelectController method is provided by the DefaultHttpControllerSelector class as shown in the below image.
The above class uses a straightforward algorithm to find the controller as:
- First, it will look at the route dictionary collection for the key “controller”.
- Secondly, it takes the value for the “controller” key and appends the string “Controller” to get the controller type name.
- Finally, it looks for a Web API controller with this type of name.
Action Selection
After selecting the controller, next, the WEB API Framework selects the action by calling the IHttpActionSelector.SelectAction method. This method takes an HttpControllerContext as a parameter and returns an HttpActionDescriptor as shown in the below image.
The default implementation for the SelectAction is provided by the ApiControllerActionSelector class as shown in the below image.
To select an action, it looks at the following algorithm:
- The HTTP method of the request.
- The “{action}” placeholder in the route template, if present.
- The parameters of the actions on the controller.
When selecting an action, the WEB API Framework only looks at the public methods of the controller excluding the constructors, events, operator overloads, and so forth, and methods that are inherited from the ApiController class.
HTTP Methods:
The WEB API Framework only chooses the action methods that match the HTTP method of the incoming request, determined as follows:
- The actions which are decorated with the HTTP attribute such AcceptVerbs, HttpDelete, HttpGet, HttpHead, HttpOptions, HttpPatch, HttpPost, or HttpPut.
- If the method names of the controller starts with “Get”, “Post”, “Put”, “Delete”, “Head”, “Options”, or “Patch”, then by convention the action supports that HTTP method.
The parameter binding is how Web API creates value for a parameter. Here is the default rule for parameter binding:
- Simple types are taken from the URI.
- Complex types are taken from the request body.
With that background, let see the action selection algorithm.
- Create a list of all the actions on the controller that match the HTTP request method.
- If the route dictionary has an “action” entry, remove actions whose name does not match this value.
- Try to match action parameters to the URI, as follows:
- For each action, get a list of the parameters that are the simple type, where the binding gets the parameter from the URI. Exclude optional parameters.
- From this list, try to find a match for each parameter name, either in the route dictionary or in the URI query string. Matches are case insensitive and do not depend on the parameter order.
- Select an action where every parameter in the list has a match in the URI.
- If more than one action meets these criteria, pick the one with the most parameter matches.
- Ignore actions with the [NonAction] attribute.
Example:
Let us consider the above points with an example.
Routes:
Controller:
HTTP request:
GET http://localhost:50470/api/student/1?version=2.1&details=1
Route Matching
The above URI matches the route named “DefaultApi”. The route dictionary contains the following elements:
- controller: “Student”
- id: “1”
Controller Selection
From the “controller” entry in the route dictionary, the WEB API Framework select the controller type is StudentController.
Action Selection
The above HTTP request is a GET request. The controller actions that support GET Request are GetAllStudents, GetStudentById, and FindStudentsByName. The route dictionary does not contain an entry for “action”, so we don’t need to match the action name.
Next, we need to match the parameter names for the actions, looking only at the GET actions.
Notice that the version parameter of GetStudentById is not considered, because it is an optional parameter.
The GetAllStudents method matches trivially. The GetStudentById method also matches, because the route dictionary contains the “id”. The FindStudentsByName method does not match.
The GetStudentById method wins because it matches one parameter, versus no parameters for GetAllStudents. The method is invoked with the following parameter values:
- id = 1
- version = 2.1
Summary:
I Hope this post will be helpful to understand the concept of Routing and Action Selection in Web API
Please share this post with your friends and colleagues.
For any queries please post a comment below.
Happy Coding 😉
0 comments:
Post a Comment
If you like this website, please share with your friends on Facebook, Twitter, LinkedIn.