Route Concept In .NET Core Application - Day Six

In the previous article of this series, we discussed how to develop a shared library in the .NET Core Application. Now, in this article, we will discuss how can we use route concept in .NET Core.

If you want to look at the previous articles of this series, please visit the links given below.

Routing functionality is responsible for mapping an incoming request to a route handler. Routes are defined in ASP.NET app and configured when the app starts. A route can optionally extract the values from the URL contained in the request and these values can then be used for the request processing. Using route information from ASP.NET app, the routing functionality is also able to generate URLs, which maps to route handlers. Therefore, routing can find a route handler based on a URL or the URL corresponding to a given route handler based on route handler information.

In Web development, routing serves to map all the incoming requests to the handlers and generate the URLs used in the responses. In ASP.NET Core, routing has been rewritten from the roots. Because routing with MVC and Web API was very similar, but both were using different frameworks (and code) to do the same thing, an important difference is that Web API supports RESTful routes, by default. For example, if a Controller’s action method name started with Post, then invoking an HTTP Post would call the method, by default. Since Microsoft decided to rebuild and unify the routing framework, what applies now for MVC, applies also for Web API. Before we dig into how to build routing, however, let’s review what are the advantages of routing for which it is important for our Application

Advantages of Routing

  1. SEO friendly - RESTfully configured routing facilitates the Search Engine Optimization (SEO) of your content. A site’s URL is one of the top criteria that impacts site ranking. By converting www.website.com/articles/show/123 to www.yourwebsite.com/how-to-peel-potatoes you encourage search engines to rank it higher for keyphrases related to “how to peel potatoes.” Also, when you have a URL that is more descriptive, it is easier for users to correctly anticipate the content, leading to increased time on page, which also impacts SEO and your overall page authority.

  2. URLs do not need to map a file - Without routing, an incoming request would be mapped to a physical file. With routing we have full control of the request, allowing us to decide what action and controller we execute when a certain HTTP request comes in.

  3. Long URLs and file extensions can be eliminated - Routing helps to shorten the URL in instances where many parameters and filters are in play. By eliminating the file extension, we can hide what kind of environment we are working in.

Routing basics

Routing uses routes (implementations of IRouter) to,

  • map incoming requests to route handlers
  • generate URLs used in responses

Generally, an app has a single collection of routes. When a request arrives, the route collection is processed in order. The incoming request looks for a route that matches the request URL by calling the RouteAsync method on each available route in the route collection. By contrast, a response can use routing to generate URLs (for example, for redirection or links) based on route information, and thus avoid having to hard-code URLs, which helps maintainability. Routing is connected to the middleware pipeline by the RouterMiddleware class. ASP.NET MVC adds routing to the middleware pipeline as part of its configuration.

Current ASP.NET Routing

Prior to going for further discussion about routing in ASP.NET Core, let’s remind ourselves about how route works in the ASP.NET 4.x.

Routing is integrated with the pipeline as an IHttpModule and when a route was resolved, it would bypass the rest of the pipeline and delegate to the final IHttpHandler through a new factory-type interface, the IRouteHandler.

  1. public interface IRouteHandler  
  2. {  
  3.    IHttpHandler GetHttpHandler(RequestContext context);  
  4. }  

It was through this IRouteHandler that MVC integrated with Routing, and this is important, because generally MVC-style URL's are extensionless, so the routing system enabled these types of URLs to be mapped to a specific IHttpHandler and in the case of MVC, this means mapping to the MVCHandler, which is the entry point for Controller/action execution. This means we didn't need to express a whole host of <httpHandler> rules for each unique route in our web.config file.

The MVC integration provided the MapRoute methods as extensions for a RouteCollection. Each route instance provides a Handler property - which by default is set to the MVCRouteHandler (through the IRouteHandler abstraction),

  1. routes.MapRoute(  
  2. "Default",  
  3. "{controller}/{action}/{id}",  
  4. new { controller = "Home", action = "Index", Id = UrlParameter.Optional });  

This method call creates a Route instance with the MVCRouteHandler set. You can always override it, as shown.

  1. var route = routes.MapRoute("Default""{controller}/{action}/{id}"new {  
  2.     controller = "Home", action = "Index", Id = UrlParameter.Optional  
  3. });  
  4. route.Handler = new MyCustomHandler();  

In current Routing (System.Web.Routing), routes are registered into a RouteCollection, which forms a linear collection of all the possible routes. When the routes are being processed against an incoming URL, they form a top-down queue, where the first Route that matches it wins. For ASP.NET 4.x, there can only be one route collection for your Application, so all of your routing requirements have to be fulfilled by this instance.

ASP.NET Core Routing

The new Routing framework is based around the concept of an IRouter,

  1. public interface IRouter {  
  2.     Task RouteAsync(RouteContext context);  
  3.     VirtualPathData GetVirtualPath(VirtualPathContext context);  
  4. }  

An instance of RouterMiddleware can be created, using any instance of IRouter. You can think of this as the root of a routing tree. Routers can be implemented any way and can be plugged directly into the pipeline, using middleware. To handle the classical routing collection (or route table), we now have an IRouteCollection abstraction, itself extending IRouter. This means that any RouteCollection instance acts as a router and can be used directly with the middleware.

Using Routing Middleware

To implement route in the .NET Core Application, first add NuGet package Microsoft.AspNetCore.Routing.

Add routing to the Service container in Startup.cs.

  1. public void ConfigureServices(IServiceCollection services)  
  2. {  
  3.    services.AddRouting();  
  4. }  

Routes must be configured in the Configure method in the Startup class. The sample given below uses API.

  • RouteBuilder
  • Build
  • MapGet Matches only HTTP GET requests
  • UseRouter

If you are configuring a single route, call app.UseRouter, which is passed in an IRouter instance. You won't need to call RouteBuilder. The framework provides a set of extension methods to creating routes such as

  • MapRoute
  • MapGet
  • MapPost
  • MapPut
  • MapDelete
  • MapVerb

Some of these methods such as MapGet require a RequestDelegate to be provided. The RequestDelegate will be used as the route handler when the route matches. Other methods in this family allow configuring a middleware pipeline, which will be used as the route handler. If the Map method doesn't accept a handler, such as MapRoute, then it will use the DefaultHandler. The Map[Verb] methods use the constraints to limit the route to the HTTP Verb in the method name.

Now, write down the code given below.

Program.cs
  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.IO;  
  4. using System.Linq;  
  5. using System.Threading.Tasks;  
  6. using Microsoft.AspNetCore.Hosting;  
  7. namespace Prog5_SimpleRoute {  
  8.     public class Program {  
  9.         public static void Main(string[] args) {  
  10.             var host = new WebHostBuilder().UseKestrel().UseContentRoot(Directory.GetCurrentDirectory()).UseIISIntegration().UseStartup < Startup > ().UseApplicationInsights().Build();  
  11.             host.Run();  
  12.         }  
  13.     }  
  14. }  
Startup.cs
  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Linq;  
  4. using System.Threading.Tasks;  
  5. using Microsoft.AspNetCore.Builder;  
  6. using Microsoft.AspNetCore.Hosting;  
  7. using Microsoft.AspNetCore.Http;  
  8. using Microsoft.Extensions.DependencyInjection;  
  9. using Microsoft.Extensions.Logging;  
  10. using Microsoft.AspNetCore.Routing;  
  11. namespace Prog5_SimpleRoute {  
  12.     public class Startup {  
  13.         // This method gets called by the runtime. Use this method to add services to the container.  
  14.         // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940  
  15.         public void ConfigureServices(IServiceCollection services) {  
  16.             services.AddRouting();  
  17.         }  
  18.         // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.  
  19.         public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) {  
  20.             loggerFactory.AddConsole();  
  21.             if (env.IsDevelopment()) {  
  22.                 app.UseDeveloperExceptionPage();  
  23.             }  
  24.             var route = new RouteBuilder(app);  
  25.             route.MapGet("", context => context.Response.WriteAsync("This is Default Route"));  
  26.             route.MapGet("part1", context => context.Response.WriteAsync("This is Sub child Route"));  
  27.             route.MapGet("cricket", context => context.Response.WriteAsync("This is Route Details for Cricket"));  
  28.             route.MapGet("detail/{rank}", context => context.Response.WriteAsync($ "Route Rank is : {context.GetRouteValue("  
  29.                 rank ")}"));  
  30.             app.UseRouter(route.Build());  
  31.             app.Run(async(context) => {  
  32.                 await context.Response.WriteAsync("Hello World!");  
  33.             });  
  34.         }  
  35.     }  
  36. }  
Now, run the project and the the different output is given below, as per the route value.
You can read the next part here,