ASP.NET Core 2.0 MVC Routing

Routing in ASP.NET Core MVC is the mechanism through which incoming requests are mapped to controllers and their actions. This is achieved by adding Routing middleware to the pipeline and using IRouteBuilder to map URL pattern (template) to a controller and action.
 
Problem

How does routing work in ASP.NET Core MVC?

Solution

In an empty project, update Startup class to add services and middleware for MVC.

  1. public void ConfigureServices(  
  2.           IServiceCollection services)  
  3.       {  
  4.           services.AddMvc();  
  5.       }  
  6.   
  7.       public void Configure(  
  8.           IApplicationBuilder app,  
  9.           IHostingEnvironment env)  
  10.       {  
  11.           app.UseMvc(routes =>  
  12.           {  
  13.               routes.MapRoute(  
  14.                   name: "goto_one",  
  15.                   template: "one",  
  16.                   defaults: new { controller = "Home", action = "PageOne" });  
  17.   
  18.               routes.MapRoute(  
  19.                   name: "goto_two",  
  20.                   template: "two/{id?}",  
  21.                   defaults: new { controller = "Home", action = "PageTwo" });  
  22.   
  23.               routes.MapRoute(  
  24.                   name: "default",  
  25.                   template: "{controller=Home}/{action=Index}/{id?}");  
  26.           });  
  27.       } 

Add HomeController to demonstrate the conventional routing (see discussion).


Add a controller named WorkController to demonstrate the attribute routing.


Discussion

Routing in ASP.NET Core MVC is the mechanism through which incoming requests are mapped to controllers and their actions. This is achieved by adding Routing middleware to the pipeline and using IRouteBuilder to map URL pattern (template) to a controller and action.

Routing Templates

Routing templates use literals and tokens (for routing parameters). Literals are matched exactly to the text in URL whereas tokens are replaced when matching a route.

To match a template, it must contain controller and action tokens as this is the key information MVC uses to locate controller/action. Other tokens in the URL are mapped to parameters of action methods using Model Binding.

When adding a route mapping, default values could be provided for tokens. This is useful when templates don’t contain controller or action tokens. Templates can also have optional tokens for action parameters.

Let’s look at an example template to understand the above points,

Notice following points,

  • Tokens are enclosed in curly braces {}. We have 3 tokens here, controller, action and id.
  • We also have a literal “contact” that will be matched to URL text.
  • Default values are provided for controller (Home) and action (Index).
  • Optional tokens are declared using question mark ?.

Following URL’s will match this template,

  • /contact/Home/Index/1: values provided for all tokens.
  • /contact/Home/Index: optional token omitted.
  • /contact/Home: default of Index used for action
  • /contact: default of Home and Index used for controller and action.
Conventional Routing

Conventional Routing establishes a convention for the URL path, such that given a template:

  • First token maps to a controller
  • Second token maps to an action
  • Third token maps to an optional id action parameter

You could omit the controller and action from the template, as long as you provide default values for them. For instance in the below route will map URL /one because defaults are supplied for required controller and action tokens,

Note

Add such specific routes before the general rule because routes are processed in order, as soon as a match is found the matching process ends.

Since routing middleware only uses controller and action tokens to map/execute an action, having multiple actions in a controller with the same name will throw an ambiguous exception. To resolve this issue, IActionConstraint attributes (e.g. HttpGet, HttpPost etc.) can be applied to actions,


Attribute Routing

Attribute Routing maps URLs by applying routing template directly on the controller and action. The existence of controller and action in the template is not mandatory for attribute routing, as they don’t play any part in the routing process.

We can use [Route] or [HttpGet] (and other verbs) attributes to specify templates. These templates can also have literals and tokens (except for controller and action tokens).

Attributes applied to the controller are merged with those on an action e.g. in the WorkControllerPageOne action can be accessed via /work/one URL,


URL Generation

Rather than hard-coding URL in our application, we can take advantage of MVC’s routing mechanisms to generate URLs. MVC has all the information to do so in the form of templates you supplied for mapping routes.

MVC provides IUrlHelper interface to abstract away the capability for URL generation. This is exposed via Url properties of controller base class, views and view components.

Two key methods of IUrlHelper to produce URLs are,

  • Action: by supplying action, controller and route values.
  • RouteUrl: by supplying action name and route values.

If controller or route values are missing from the method’s parameters MVC will pick up these from the current request or method parameters (aka ambient values). The below method is in MobileController,


Route values are supplied as anonymous object,


If MVC can’t map these values to URL tokens, these are concatenated with the URL as query string parameters,


For attribute routing, the URL is constructed by looking at the [Route] provided on an action.

A convenience method on ControllerBase class is RedirectToAction that uses URL generation to produce an action result, which redirects user request,


IUrlHelper

To inject IUrlHelper as a dependency, you’ll need to first add it to the service container,

Sample

The sample source code has three controllers to demonstrate conventional routing, attribute routing, and URL generation respectively. The best way to understand the routing would be to download the code and play with it, altering templates to see how routing works.

Source Code

GitHub