How to use endpoint routing in ASP.NET Core 3.0 MVC

Learn how to implement endpoint routing in ASP.NET Core 3.0 MVC to bring more flexibility and functionality to your applications

How to use endpoint routing in ASP.NET Core 3.0 MVC
Koto Feja / Getty Images

ASP.NET Core MVC is the .NET Core counterpart of the ASP.NET MVC framework. You can take advantage of ASP.NET Core MVC to build cross-platform, scalable, high-performance web applications and APIs using the Model-View-Controller design pattern. ASP.NET Core takes advantage of routing to map incoming requests to respective controller actions. 

You can learn the basics of routing in ASP.NET Core from my earlier article, “Demystified: Routing in ASP.NET Core.” This article presents a discussion of how we can use endpoint routing in ASP.NET Core 3.0 MVC.

Endpoint routing is a feature newly introduced in ASP.NET Core that enables you to provide routing information to middleware in the request processing pipeline. Before the introduction of endpoint routing, routing resolution in ASP.NET Core MVC was performed at the end of the request processing pipeline. As a result, route information (such as which action method needs to be executed) was unknown to any middleware processing a request before the MVC middleware in the request processing pipeline. Incidentally, endpoint routing is available as part of ASP.NET 3.0 and later versions.

Endpoint routing matches HTTP requests to endpoints early in the middleware pipeline instead of at the end. This allows middleware later in the pipeline to access the resolved endpoint and apply additional processing. In other words, endpoint routing decouples the route matching and endpoint dispatching functions, giving you the flexibility to combine different middleware (MVC, CORS, Razor Pages, Blazor, etc.) in your applications. 

To work with the code examples provided in this article, you should have Visual Studio 2019 installed in your system. If you don’t have a copy of it, you can download Visual Studio 2019 here

Create an ASP.NET Core MVC project

First off, let’s create an ASP.NET Core project in Visual Studio. Assuming Visual Studio 2019 is installed in your system, follow the steps outlined below to create a new ASP.NET Core MVC project in Visual Studio.

  1. Launch the Visual Studio IDE.
  2. Click on “Create new project.”
  3. In the “Create new project” window, select “ASP.NET Core Web Application” from the list of templates displayed.
  4. Click Next.
  5. In the “Configure your new project” window shown next, specify the name and location for the new project.
  6. Click Create.
  7. In the “Create a New ASP.NET Core Web Application” window, select .NET Core as the runtime and ASP.NET Core 3.0 (or later) from the drop-down list at the top. 
  8. Select “Web Application (Model-View-Controller)” as the project template.
  9. Ensure that the check boxes “Enable Docker Support” and “Configure for HTTPS” are unchecked as we won’t be using those features here.
  10. Ensure that Authentication is set as “No Authentication” as we won’t be using authentication either.
  11. Click Create.

This will create a new ASP.NET Core project in Visual Studio. We’ll use this project to implement endpoint routing in the subsequent sections of this article.

Create a new controller in ASP.NET Core 3.0 MVC

In the Solution Explorer Window, select the Controllers folder in the project, right-click and then click on Add->Controller… to create a new controller. Specify the name of the controller class as AuthorController. Next, replace the code of the AuthorController class with the following code.

[Route("api/[controller]")]
    [ApiController]
    public class AuthorController : ControllerBase
    {
        readonly Repository repository = new Repository();
        [HttpGet]
        public ActionResult GetAuthors()
        {
            var records = repository.GetAllAuthors();
            return Ok(records);
        }
    }

We’ll use the AuthorController in the subsequent sections of this article.

Understand routing in ASP.NET Core

Routing is a feature that exposes endpoints and matches incoming HTTP requests to your controller's action methods. The routing middleware pertaining to the Microsoft.AspNetCore.Routing namespace is responsible for handling requests and responses, inspecting requests and matching them to endpoints, and even modifying the request and response messages that flow through the request processing pipeline.

Convention routing vs. attribute routing

You can specify routing in your action methods in two different ways — convention-based routing and attribute-based routing.

The following code snippet illustrates how you can use convention routing in the Configure method of the Startup class.

app.UseMvc(routes =>
{
    routes.MapRoute(
        name: "default",
        template: "{controller=Author}/{action=GetAuthors}/{id?}");
});

When using attribute-based routing you would mention route on your controller or the action method. You can define multiple routes for the same action method. Here is an example that illustrates this.

public class AuthorController : Controller
{
    [Route("")]
    [Route("Home")]
    [Route("Home/Index")]
    public IActionResult Index()
    {
        return View();
    }
     [Route("Home/GetAuthor/{id:int}")]
    public IActionResult GetAuthor(int id)
    {
        ViewBag.Id = id;
        return View();
    }
}

Route definitions in ASP.NET Core 3.0 MVC

When you create a new ASP.NET Core 3.0 MVC application, a default route will be created for you by Visual Studio. This is how it would look.

app.UseEndpoints(endpoints =>
{
    endpoints.MapControllerRoute(
        name: "default",
        pattern: "{controller=Home}/{action=Index}/{id?}");
}

The route definition shown here consists of two parameters — the name of the route and the route pattern. This route will match the following URLs.

/Home/Index
/Author/Index
/Author/Index/12

UseRouting vs. UseEndpoints in ASP.NET Core 3.0 MVC

Routing takes advantage of a pair of middleware components that are registered using the UseRouting and UseEndpoints extension methods. While the former is used to match a request to an endpoint, the latter is used to execute a matched endpoint.

Note that the UseRouting middleware should be configured ahead of all other middleware including authentication, authorization, and any custom middleware. By contrast, the UseEndpoints middleware should be configured at the end. The following code snippet illustrates this.

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Home/Error");
            }
            app.UseStaticFiles();
            app.UseRouting();
            app.UseAuthorization();
            app.UseEndpoints(endpoints =>
            {
               endpoints.MapControllerRoute(
               name: "default",
               pattern: "{controller=Author}/{action=GetAuthor}/{id?}");
            });
        }

If you want to check the route metadata at runtime, you can use the following code and debug it in Visual Studio.

app.Use(async (context, next) =>
{
 var endPoint = context.GetEndpoint();
 var routes = context.Request.RouteValues;
});

Configure routing in ASP.NET Core 3.0 MVC

You can set up routing in your ASP.NET Core 3.0 MVC application easily. For this you would need to make a couple of changes to the Startup class. First off, you should call the AddRazorPages method as shown below.

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

Next, you should call the MapRazorPages method as shown below. This method when called will add the Razor Pages services, options, and conventions to the pipeline.

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
           //Usual code
            app.UseEndpoints(endpoints =>
            {
                endpoints.MapRazorPages();
                endpoints.MapControllerRoute(
                name: "default",
                pattern:
                "{controller=Author}/
                 {action=GetAuthor}/{id?}");
            });
        }

Use named routes in ASP.NET Core 3.0 MVC

Note that you can specify a name for a route so that you can use multiple routes having the same parameters. Such routes are known as named routes. The following code snippet illustrates how named routes can be used.

app.UseEndpoints(endpoints =>
{
    endpoints.MapControllerRoute(
    name: "default",
    pattern: "{controller=Author}/{action=GetAuthors}/{id?}");
}

Set route defaults in ASP.NET Core 3.0 MVC

You can also explicitly set route defaults as shown in the code snippet below.

endpoints.MapControllerRoute(
    name: "default",
    pattern: "{controller}/{action}/{id?}",
    defaults: new {controller = "Home", action = "Index"});

Use MapRazorPages in ASP.NET Core 3.0 MVC

You can take advantage of the MapRazorPages extension method to enable routing for your Razor view pages. The following code snippet shows how this can be achieved.

app.UseEndpoints(endpoints =>
{
  endpoints.MapRazorPages();
});

Use mixed routing in ASP.NET Core 3.0 MVC

Note that you can use attribute-based routing for some controllers and actions and convention-based routing on other controllers and action methods. Although it is perfectly valid to use both, it should be noted that you cannot have attribute-based routing and convention-based routing in the same action method.

ASP.NET 3.0 gives us an extensible and modular framework for working with endpoints, URLs, and middleware. I’ll discuss routing in more depth in a future article here. We’ll explore the advanced routing features in ASP.NET Core 3.0 such as route templates, route constraints, custom route constraints, and more.

How to do more in ASP.NET and ASP.NET Core:

Copyright © 2020 IDG Communications, Inc.

How to choose a low-code development platform