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.
- Launch the Visual Studio IDE.
- Click on “Create new project.”
- In the “Create new project” window, select “ASP.NET Core Web Application” from the list of templates displayed.
- Click Next.
- In the “Configure your new project” window shown next, specify the name and location for the new project.
- Click Create.
- 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.
- Select “Web Application (Model-View-Controller)” as the project template.
- Ensure that the check boxes “Enable Docker Support” and “Configure for HTTPS” are unchecked as we won’t be using those features here.
- Ensure that Authentication is set as “No Authentication” as we won’t be using authentication either.
- 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:
- How to use in-memory caching in ASP.NET Core
- How to handle errors in ASP.NET Web API
- How to pass multiple parameters to Web API controller methods
- How to log request and response metadata in ASP.NET Web API
- How to work with HttpModules in ASP.NET
- Advanced versioning in ASP.NET Core Web API
- How to use dependency injection in ASP.NET Core
- How to work with sessions in ASP.NET
- How to work with HTTPHandlers in ASP.NET
- How to use IHostedService in ASP.NET Core
- How to consume a WCF SOAP service in ASP.NET Core
- How to improve the performance of ASP.NET Core applications
- How to consume an ASP.NET Core Web API using RestSharp
- How to work with logging in ASP.NET Core
- How to use MediatR in ASP.NET Core
- How to work with session state in ASP.NET Core
- How to use Nancy in ASP.NET Core
- Understand parameter binding in ASP.NET Web API
- How to upload files in ASP.NET Core MVC
- How to implement global exception handling in ASP.NET Core Web API
- How to implement health checks in ASP.NET Core
- Best practices in caching in ASP.NET
- How to use Apache Kafka messaging in .NET
- How to enable CORS on your Web API
- When to use WebClient vs. HttpClient vs. HttpWebRequest
- How to work with Redis Cache in .NET
- When to use Task.WaitAll vs. Task.WhenAll in .NET