Introduction
When it comes to listing the best practices for REST APIs, the mechanism, Routing always makes its place on the top of the stack. Today, in this article, we will dirty our hands with Routing concepts with REST (web) APIs, specific to .NET Core.
For novice APIs developers, technical consultants, and all other IT professionals associated with REST APIs, especially with a Microsoft technologies stack, this article will explain the importance and capabilities of Routing focusing Attribute Routing in REST APIs with Microsoft’s .NET Core.
Overview
Routing, an open debatable topic among many in the developer community, is an interesting feature in which to deep dive. Routing is a functionally based tag or Uri template used by APIs to match the desired action or methods expected to be executed. There are two types or rather two different types of Routing being used during development. Namely, ‘Convention-based Routing’ the elder son in the REST routing family followed by ‘Attribute Routing’ the most lovable son to date. As mentioned earlier it’s an open debatable topic over using which type of Routing mechanics during APIs development and designing phase as well.
In ‘Convention-based Routing’, route templates are defined by developers as per requirement, basically a set of strings of type text decorated with parameters. Once the request is received, it tries to match requested URI with this defined route templates. The only merit of using this routing type is, templates are defined at a single location in application solution structures, leveraging the template rules religiously across the controllers and actions.
Then, why is Attribute routing important? Yes, it is not only important but strongly recommended for API development by developers and architects across the communities. Though convention-based routing has its own Pros, while building a good API, there are few considerations, where this type of routing is not advisable. There are common URI patterns in REST APIs, which are tough to support by convention-based routing. Consider, a set of Response data or resources, are often clubbed with their hierarchical data or child resources. For eg. Departments have Employees, Songs have singers, Movies have actors and so on. URIs expected in such scenarios are,
/movies/1/actors
In the case of multiple controllers and huge resources this type of URI is difficult though achievable using convention-based routing, but at the cost of scaling and performance. This hits the key consideration area of designing scalable APIs. Here is where another routing type, Attribute Routing, plays a role.
Attribute Routing
What is Attribute Routing?
Technically, Attribute routing is all about attaching a route, as an attribute, to a specific controller or action method. Decorating Controller and its method with [Route] attribute to define routes is called Attribute Routing. In simpler terms, using [Route] attribute with controllers and method is Attribute Routing.
[Route ("api/customers/{id}/orders")]
It started from Web API 2 and now is the most recommended and adapted Routing type in RESTful APIs design and development.
Why use Attribute Routing?
As the name indicates, attribute routing uses attributes to define routes. Attribute routing gives you precise control over the URIs than convention-based routing in your APIs. Above described scenario of Hierarchical resources can be easily achieved by Attribute Routing, with making no compromise with the scalability of APIs.
Also, versioning APIs, overloading URI segments and multiple parameter type patterns can be achieved through attribute routing with ease.
Working with Attribute Routing
Any route attribute on the controller makes all actions in the controller attribute routing. Defining route attribute to the action or the controller takes precedence over conventional routing. Let’s be more precise to .NET Core APIs, it comes by default with Attribute routing. Attribute routing requires detailed input to specify a route. However, it allows more control of which route template applies to each action.
Configuring
When you create a WEB API with .NET Core framework, you can notice in its Startup.cs file,
- void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) {
- app.UseMvc();
- }
This declaration of, ‘app.UseMvc()’ at configure section, enables Attribute Routing. This are by-default configurations of .NET Core applications. Explicit configurations thus are not required for enabling Attribute routing for .NET Core Web APIs.
Below namespace is used for decorating [Route] as an attribute.
using Microsoft.AspNetCore.Mvc;
The core difference with Web API over MVC routing is that it uses the HTTP method, not the URI path, to select the action. Attribute routing also uses HTTP Action verbs to define action against methods under controller, as requested.
[HttpGet], [HttpPost], HttpPut("{id}")], [HttpDelete("{id}")] and all other documented action verbs.
In .NET Core projects, by default, Controllers are decorated with CRUD methods specifying respective HTTP action verbs.
Below is the default controller being created by .NET Core,
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Threading.Tasks;
- using Microsoft.AspNetCore.Mvc;
- namespace WebAPIwiithCore.Controllers
- {
- [Route("api/[controller]")]
- publicclassMoviesController : Controller
- {
- // GET api/values
- [HttpGet]
- publicIEnumerable<string> Get()
- {
- returnnewstring[] { "value1", "value2" };
- }
- // GET api/values/5
- [HttpGet("{id}")]
- publicstring Get(int id)
- {
- return"value";
- }
- // POST api/values
- [HttpPost]
- publicvoid Post([FromBody]string value)
- {
- }
- // PUT api/values/5
- [HttpPut("{id}")]
- publicvoid Put(int id, [FromBody]string value)
- {
- }
- // DELETE api/values/5
- [HttpDelete("{id}")]
- publicvoid Delete(int id)
- {
- }
- }
- }
If you notice carefully, controller class ‘ValuesController’, is decorated by route,
[Route("api/[controller]")]
The feature is introduced in .NET Core framework known as Route token. The token [controller] replaces the values of the controller name from the action or class where the route is defined.
Here controller name is Values decorated by Route Controller token,
- [Route("api/[controller]")]
- publicclassValuesController : Controller{ ... }// Matches '/api/Values’
Now let’s change controller name to MoviesController;
- [Route("api/[controller]")]
- publicclassMoviesController : Controller{ ... }// Now Matches '/api/Movies’
Here, URI ‘api/values’ are working perfectly earlier, now it will throw an error (404 not found). Changing URI with ‘api/Movies’ will provide the desired response.
The same applies for [action] and [area] with their respective action methods and areas.
Now, let’s consider the below example,
- [Route("api/[controller]")]
- publicclassMoviesController: Controller {
- [HttpGet]
- publicIEnumerable < string > Get() {
- returnnewstring[] {
- "value1",
- "value2"
- };
- }
- [HttpPost]
- publicvoid Post([FromBody] string value) {
- return;
- }
- }

Danny KonstadtPosted Oct 27, 2018, 3:30 AM
Excellent, exactly what I was looking for!
Paulo StradiotiPosted Jun 2, 2018, 9:00 AM
Great article
Lexi BalkanPosted May 26, 2018, 3:53 PM
How would I create an endpoint to the request https://localhost:44329/api/scoInfo?activityId=1&studentId=1×tamp=1527357844844 using attribute routing in the controller?