Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

ASP.NET Core 2.0 MVC Routing

0.00/5 (No votes)
1 Sep 2017 1  
How does routing work in ASP.NET Core MVC. Continue reading...

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:

public void ConfigureServices(
            IServiceCollection services)
        {
            services.AddMvc();
        }

        public void Configure(
            IApplicationBuilder app,
            IHostingEnvironment env)
        {
            app.UseMvc(routes =>
            {
                routes.MapRoute(
                    name: "goto_one",
                    template: "one",
                    defaults: new { controller = "Home", action = "PageOne" });

                routes.MapRoute(
                    name: "goto_two",
                    template: "two/{id?}",
                    defaults: new { controller = "Home", action = "PageTwo" });

                routes.MapRoute(
                    name: "default",
                    template: "{controller=Home}/{action=Index}/{id?}");
            });
        }

Add a controller HomeController, to demonstrate conventional routing (see discussion):

MVC - Routing - HomeController

Add a controller WorkController, to demonstrate attribute routing (see discussion):

MVC - Routing - WorkController

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:

contact/{controller=Home}/{action=Index}/{id?}

Notice the 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 URLs 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:

routes.MapRoute(
       name: "goto_one",
       template: "one",
       defaults: new { controller = "Home", action = "PageOne" });

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 on actions:

MVC - Routing - ActionConstraint

Attribute Routing

Attribute Routing map 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 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 on the controller are merged with those on an action e.g. in the WorkController, PageOne action can be accessed via /work/one URL:

MVC - Routing - Attribute Routing

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 current request or method parameters (aka ambient values). The below method is in MobileController:

MVC - Routing - URL Gen 4

Route values are supplied as anonymous object:

MVC - Routing - URL Gen 1

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

MVC - Routing - URL Gen 2

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:

MVC - Routing - URL Gen 3

IUrlHelper

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

services.AddSingleton<IActionContextAccessor, ActionContextAccessor>();
            services.AddScoped<IUrlHelper>(factory =>
            {
                var actionContext = factory.GetService<IActionContextAccessor>()
                                           .ActionContext;
                return new UrlHelper(actionContext);
            });

Sample

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

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here