Routing and Action Selection in Web API

Routing and Action Selection in Web API

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:

  1. Matching the URI to a route template.
  2. Selecting a controller.
  3. Selecting an action.
Route Templates in ASP.NET Web API

We can configure routes to the Route table within the Register method WebApiConfig class by using the MapHttpRoute extension method as shown in the below image.

Selecting Controller and Action in ASP.NET Web API

A route template in ASP.NET Web API Application looks very much similar to a URI path, but it can have placeholder values that are indicated with curly braces as shown below. 
routeTemplate: “api/{controller}/{id}”

When we create a route, it is also possible to provide default values for some or all of the placeholders as shown below.
defaults: new { id = RouteParameter.Optional }

We can also provide some constraints which will restrict how a URI segment can match a placeholder as shown below.
constraints: new { id = @”\d+”}

The ASP.NET 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}“.

  1. The “{controller}” placeholder provides the name of the controller.
  2. Similarly, the “{action}” placeholder provides the name of the action. In ASP.NET 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.
Defaults

If you provide a default value for a placeholder, then the route will match a URI that is missing those segments. For example:

Routing and Action Selection in Web API

The URI “http://localhost/api/student/public” matches this route. The “{category}” segment is assigned the default value “all”.

Route Dictionary

When the ASP.NET 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.

Routing and Action Selection in Web API

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 is assigned with this value, then the value will not be added to the route dictionary. For example:

Routing and Action Selection in Web API

For the URI path “api/student/public“, the route dictionary will contain two elements such as:

  1. controller: “student”
  2. category: “all”

For the URI path “api/student/public/cse/101“, the route dictionary will contain three elements such as:

  1. controller: “student”
  2. category: “cse”
  3. id: “101”

The defaults can also include a value that does not appear anywhere in the route template. If the route matches, that value is also get stored in the dictionary. For example:

Routing and Action Selection in Web API

If the URI path is “api/root/101“, then the dictionary will contain two elements such as:

  1. controller: “Employee”
  2. id: “101”
Selecting a Controller

The Controller selection in ASP.NET Web API is handled by the IHttpControllerSelector.SelectController method.

Routing and Action Selection in Web API

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.

Routing and Action Selection in Web API

The above class uses a straightforward algorithm to find the controller as:

  1. First, it will look at the route dictionary collection for the key “controller”.
  2. Secondly, it takes the value for the “controller” key and appends the string “Controller” to get the controller type name.
  3. Finally, it looks for a Web API controller with this type of name.

For example, if the route dictionary contains the key-value pair “controller” = “Student”, then the controller type is “StudentController”. If there is no matching type found, or it found multiple matches, then the ASP.NET Web API Framework simply returns an error to the client.

Action Selection in ASP.NET Web API

After selecting the controller, next, the ASP.NET 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.

Routing and Action Selection in Web API

The default implementation for the SelectAction is provided by the ApiControllerActionSelector class as shown in the below image.

Routing and Action Selection in Web API

To select an action, it looks at the following algorithm:

  1. The HTTP method of the request.
  2. The “{action}” placeholder in the route template, if present.
  3. The parameters of the actions on the controller.

Before looking at the selection algorithm, first, we need to understand which methods on the controller class are considered as “actions” methods? When selecting an action, the ASP.NET 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 ASP.NET Web API Framework only chooses the action methods that match the HTTP method of the incoming request, determined as follows:

  1. The actions which are decorated with the HTTP attribute such AcceptVerbs, HttpDelete, HttpGet, HttpHead, HttpOptionsHttpPatchHttpPost, or HttpPut.
  2. 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.
Parameter Bindings: 

The parameter binding is how ASP.NET Web API creates value for a parameter. Here is the default rule for parameter binding:

  1. Simple types are taken from the URI.
  2. Complex types are taken from the request body.

It is also possible to change the default Parameter Binding in ASP.NET Web API.

With that background, let see the action selection algorithm.
  1. Create a list of all the actions on the controller that match the HTTP request method.
  2. If the route dictionary has an “action” entry, remove actions whose name does not match this value.
  3. Try to match action parameters to the URI, as follows:
  4. 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.
  5. 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.
  6. Select an action where every parameter in the list has a match in the URI.
  7. If more than one action meets these criteria, pick the one with the most parameter matches.
  8. Ignore actions with the [NonAction] attribute.

Step3 is probably the most confusing step. The basic idea is that a parameter can get its value either from the URI or from the request body, or from a custom binding. For parameters that come from the URI, we want to ensure that the URI actually contains a value for that parameter, either in the path (via the route dictionary) or in the query string.

Example:

Let us consider the above points with an example.

Routes:

Routing and Action Selection in Web API

Controller:

Routing and Action Selection in Web API

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:

  1. controller: “Student”
  2. id: “1”

The route dictionary does not contain the query string parameters, “version” and “details”, but these will still be considered during action selection.

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.

Routing and Action Selection in Web API

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:

  1. id = 1
  2. version = 2.1

Notice that even though the version was not used in the selection algorithm, the value of the parameter comes from the URI query string.

In the next article, I am going to discuss Web API Attribute Routing with examples. Here, in this article, I try to explain the Routing and Action Selection in Web API step by step with some examples. I hope this Routing and Action Selection in Web API article will help you with your needs. I would like to have your feedback. Please post your feedback, question, or comments about this article.

1 thought on “Routing and Action Selection in Web API”

Leave a Reply

Your email address will not be published. Required fields are marked *