Application URL Routing
.NET .NET Core ASP.NET Core C# MVC

An Overview of Routing in ASP.NET and ASP.NET Core Applications

Welcome to today’s post.

In today’s post I will be providing an overview of routing in ASP.NET and ASP.NET Core web applications.

In most web application routing frameworks, the method of routing works by matching a name or route within a URL address specified from the browser with a segment within a URL route, which corresponds to a physical page, or to a virtual route specified within a routing table, or by a convention determined by a hierarchy of nested sub-folders containing the physical target page.

As a .NET developer, you will have come across one of the many variations of web application routing that have been introduced along with each version of .NET Framework, .NET Core, and with the Visual Studio development tools. In addition, the variations of convention-based routing that were introduced from ASP.NET 3.5 Web Forms and continuing onto attribute-based routing, which was introduced since ASP.NET 4.5. Below is an overview of convention-based routing:

With convention-based routing, we rely on the use of a routing table to direct the HTTP request onto the correct controller and action method and use the parameter type to match action methods that share the same name. In addition, the methods are matched according to the http verb GET, POST, PUT, DELETE that prefixes the action method in the controller.

Below is an overview of attribute-based routing:

With attribute-based routing, we no longer require the use of a routing table, with each HTTP request URI being matched to the patterns within the attribute segments in the action method.

In the next two sections we will review routing in legacy ASP.NET 3.5 and ASP.NET 4.5 web applications.

Routing in Legacy ASP.NET 3.5 Web Forms Applications

With the legacy ASP.NET web forms applications using .NET framework 3.5, routing is based on URL routing, which is based on an input URL pattern which is then mapped to an existing page URL through a handler that takes the URL pattern and converts it to the full URL of the target page. With this approach, we would specify the UrlRoutingModule and a UrlRoutingHandler within the web application’s web.config file’s system.webServer/modules and system.webServer/handlers sections. The custom URL routing handler would then be an axh file that consisted of a class implemented from the IRouteHandler interface.  The handler would then be registered within the Application_Start event within a Global.asax file.   

Routing in ASP.NET 4.5 Web Forms Applications

With legacy ASP.NET web forms applications using .NET framework 4.5. the routing mechanism improved to deliver URL routing based on routing tables from the system.web.routing namespace. Within the Application_Start event within the Global.asax.cs source file, URL routing handlers are enabled by passing RouteTable.Routes into the static RouteConfig.RegisterRoutes() method then custom routes are initialised by calling the RoutesCollection class method MapPageRoute() to map each URI routing pattern to an actual .aspx page.  

In the next section we will see how routing works in ASP.NET MVC applications.

Routing in ASP.NET MVC Applications

The default routing behaviour of ASP.NET MVC applications is similar to ASP.NET 4.5 web forms in that is also uses a static RouteConfig.RegisterRoutes() method to register custom routes using the RouteCollection class method MapRoute() to map a URI routing pattern to an MVC controller action. The URL route is based on the convention:

/{controller name}/{action name}/{parameter value}

Where:

the segment [controller name] is the name of a controller class.

the segment [action name] is the name of an action method within the controller class.

the segment [parameter value] is the value of a parameter passed into the action method within the controller class.

We will review routing of Web API and Web API 2 applications in the next two sections.

ASP.NET Web API Routing

With routing in ASP.NET Web API applications, routing works with a convention-based routing by defining routes within the WebApiConfig.cs file within the App_Start folder, that maps a URI template pattern onto a physical web page.

Convention-based routing of Web API requests works by passing a URL routing template pattern of the formats:

api/{controller}/{id}

OR

api/{controller}/{action}/{id}

The above URIs maps to an action through the routes.MapHttpRoute() method. The above attribute routing is a conventions-based routing, which goes through the Web API controller, whereas URL template patterns using the {controller}/{action}/{id} format go through an MVC controller. This means that Web API applications routing conventions support both convention-based routing and MVC type routing.

When we run a HTTP request such as:

GET: api/books/1

Within the API controller, the convention-based routing looks for an action that is prefixed by the verb Get, then followed by the action name GetBook(..) with an integer parameter. If it does not find a method with that name, it will try to match an action method prefixed by Get and the input parameter type.

The HTTP verbs such as GET, POST, PUT, and DELETE can be specified for an action by decorating action method with these HTTP verbs. An example is below:

[HttpGet]
public string Details(int id)

Which did not need us to specify the action method according to a convention.

ASP.NET Web API 2 Routing

With routing in ASP.NET Web API 2 applications, the routing is no longer limited to using convention-based routing strategy. It can also use a method based on routing attributes. In addition, both conventional and attribute routing can be combined within the same Web API 2 application.

Attribute routing is enabled within a Web API 2 application by calling the HttpConfiguration class method MapHttpAttributeRoutes() within the static Register() method in the WebApiConfig.cs file.

In addition, convention-based routing can also be enabled in the same Register() static method using the HttpConfiguration class method Routes.MapHttpRoute() method to map each routing template to an API controller.

The improvement with the Web API 2 attribute-based routing framework is that it supports both convention-based routing and attribute-based routing.

With attribute-based routing you get the benefit of being able to route based on hierarchical levels that are common in REST API calls.

To apply attribute routes, we use the [Route] prefix in the action method. The route prefix contains the routing pattern that is used to match a request to the action method.

The attribute routing matching algorithm works by attempting to match each individual segment from the URI template into the corresponding route declared within each action methods routing attribute.

So, for example, the following action method with a routing attribute:

[Route(“books/{bookId}/loans”)]
Public List<Loans> GetLoansByBook(int bookId)

The above API method will be matched with the following HTTP request:

GET: /books/1/loans

The segments books and loans, including the integer parameter, bookId in the URI template “books/{bookId}/loans” are matched to the same segments in the HTTP request.

As we can see with attribute-based routing, there is no need to structure routing template URIs in terms of hierarchical ordering of business entities which fit a convention, so controller actions can be localized within logically related controllers that are matched by more complex routes that can include unconventional hierarchies of logical entities and parameters. In the example above, we can mix the Book and Loan entities in the same controller and match action methods that utilize more than one entity.

Routing in ASP.NET Core

In ASP.NET Core applications, during the application startup (in Startup.cs or Program.cs depending on the version of .NET Core) the application middleware UseRouting() is used to enable application route matching from route templates.

From the Web API and Web API 2 based routing, we can enable convention-based and controller based routing middleware using MapControllerRoute(). To make of attribute-based routing, use MapControllers().

Below is how the mixed routing architecture works within an ASP.NET Core web application.

Below is an example of attribute routing based on HTTP verb attributes for a REST API controller:

[HttpGet("api/Book/List")]
public async Task<List<BookViewModel>> List()
{
    …
}

The use of the Route attribute in action methods is identical to what I showed for Web API 2 attribute routing. In addition, we can decorate the controller class level with the Route attribute to establish additional hierarchies of routes in ASP.NET Core Web API requests.

Below is one example of how to use hierarchical routes:

[Route("Books")]
public class BooksApiController : ControllerBase
{
    [Route(“List”)]
    public IActionResult ListBooks()
    {
        …
    }

    [Route("{id}")]
    public IActionResult GetBook(int id)
    {
        …
    }
}

The routes:

/Books/List matches the action ListBooks()

/Books/1 matches the action GetBook(int id)

With hierarchical routes, if the controller route matches but none of the action routes match, then the request will result in a 404 error (not found).

We have seen from the above overview, the variety of ways in which routing has evolved from the legacy ASP.NET 3.5 framework onto more recently, ASP.NET Core. This will give us an appreciation of the complexities behind routing, how convention-based routing and attribute-based routing is setup within ASP.NET applications, and how either or both routing architectures can be incorporated into ASP.NET Core web applications. In addition, an understanding will help us to migrate ASP.NET applications to ASP.NET Core applications.

That is all for today’s post.

I hope you have frond this post useful and informative.

Social media & sharing icons powered by UltimatelySocial