Cover

Endpoint Routing in ASP.NET Core 3.0

September 9, 2019
No Comments.

Endpoint Routing was introduced in ASP.NET Core 2.2 but has been made a first class citizen of ASP.NET Core in 3.0. While you’re old projects will continue to work without it, upgrading to Endpoint Routing will improve your applications.

Endpoint Routing is a system to handle routing across different middleware systems (e.g. MVC, Razor Pages, Blazor, SignalR and gRPC). By having endpoints that work with each other, you can think of a system more holistically then having terminal middleware that don’t talk to each other. Let’s see what that actually means in practice.

If you’ve seen the new project template, you’ve probably already noticed that setting up RazorPages and MVC look a bit different. First in the ConfigureServices:

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

Instead of AddMvc(), you can use AddControllers (for just API routing) or AddControllersWithViews() to get the services for View production too. The real point of Endpoint routing comes in the Configure method:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
  //...
  
  app.UseRouting();

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

Notice that you’re opting into Routing separately from Endpoints. But by adding routes inside UseEndpoints, we’re able to treat them with a singlar middleware. But why?

Endpoint Routing is creating a route table across the different sets of middleware. This way you can route a variety of subsystems. The reality is that I don’t think of Razor Pages, MVC, SignalR, etc. as choices for architectural style. I actually see them as complimentary. Why bother with a Controller-View for a simple ‘About’ page? In most of my apps I use both. Once you start adding Blazor, gRPC, and others…it gets even more complex. So instead of some middleware ‘winning’ by being the terminal middleware, it simply allows them to coalese together.

One place where you can see this making sense is in IUrlHelper (or really LinkGenerator by extension). Here I have a small list of links in an app:

  <ul>
    <li>About: @Url.RouteUrl(new { page = "/About" })</li>
    <li>Contact: @Url.RouteUrl(new { action = "contact" })</li>
    <li>Product 1: @Url.RouteUrl(new { action = "product", id = 1 })</li>
    <li>Product 100: @Url.RouteUrl(new { action = "product", id = 100 })</li>
  </ul>

Because some the the links point to Razor Pages and some are using MVC, I can treat them as similar to each other. The only difference is really what route parameters are used (page for Razor Pages and controller/action for MVC).

This also allows for third parties to join the the party. Imagine if you wanted to use an API layer that didn’t rely on MVC but wanted to use the Routing subsystem. You could intermingle them with little or no problem.

I like where this is headed!