Attribute Routing in ASP.NET Web API 2

In this article you will learn about Attribute Routing in ASP.NET Web API2.

In the last article we’ve seen how can we inject multiple parameters to Web API method; the same can be achieved using route attribute in Web API. Though there were small challenges which I will also describe in this article which may reduce your development time for sure. An excerpt from asp.net about routing,

"Routing is how Web API matches a URI to an action. Web API 2 supports a new type of routing, called attribute routing. As the name implies, attribute routing uses attributes to define routes. Attribute routing gives you more control over the URIs in your web API. For example, you can easily create URIs that describe hierarchies of resources.The earlier style of routing, called convention-based routing, is still fully supported. In fact, you can combine both techniques in the same project".

The website also stated why Attribute Routing is required,

"The first release of Web API used convention-based routing. In that type of routing, you define one or more route templates, which are basically parameterized strings. When the framework receives a request, it matches the URI against the route template. One advantage of convention-based routing is that templates are defined in a single place, and the routing rules are applied consistently across all controllers".

Enabling Attribute Routing

To enable attribute routing, call MapHttpAttributeRoutes during configuration. This extension method is defined in the System.Web.Http.HttpConfigurationExtensions class. Kindly have a look at the code shown below as well as an image depicted below:

  1. namespace WebApiDemo  
  2. {  
  3.     public static class WebApiConfig  
  4.     {  
  5.   
  6.         public static void Register(System.Web.Http.HttpConfiguration config)  
  7.         {  
  8.             config.MapHttpAttributeRoutes();  
  9.   
  10.             config.Routes.MapHttpRoute(  
  11.                 name: "DefaultApi",  
  12.                 routeTemplate: "api/{controller}/{action}/{id}",  
  13.                 defaults: new  
  14.                 {  
  15.                     id = RouteParameter.Optional  
  16.                 }  
  17.             );  
  18.         }  
  19.     }  
  20. }  
Here, I’ve a simple controller, Employees, which has the following Action Method defined below and performs a set of statement like fetch a record from collection.GetDetails() action method takes one parameter and has its own specific routes while GetEmployeeByID() action method takes two parameters as arguments and has its own defined route.

GetDetails
  1. [Route("api/{employees}/{id}")]  
  2. public Employee GetDetails(int id)  
  3. {  
  4.     return listEmp.First(e => e.ID == id);  
  5. }  
GetEmployeeByID
  1. [HttpGet]  
  2. [Route("api/{employees}/{id}/{userName}")]  
  3. [ActionName("GetEmployeeByID")]  
  4. public Employee Get(int id, string userName)  
  5. {  
  6.     return listEmp.First(e => e.ID == id);  
  7.     SqlDataReader reader = null;  
  8.     SqlConnection myConnection = newSqlConnection();  
  9.     myConnection.ConnectionString = @ "Server=.;Database=DBCompany;User ID=sa;Password=db@1234;";  
  10.   
  11.     SqlCommand sqlCmd = newSqlCommand();  
  12.     sqlCmd.CommandType = CommandType.Text;  
  13.     sqlCmd.CommandText = "Select * from tblEmployee where EmployeeId=" + id + "";  
  14.     sqlCmd.Connection = myConnection;  
  15.     myConnection.Open();  
  16.     reader = sqlCmd.ExecuteReader();  
  17.     Employee emp = null;  
  18.     while (reader.Read())  
  19.     {  
  20.         emp = new Employee();  
  21.         emp.EmployeeId = Convert.ToInt32(reader.GetValue(0));  
  22.         emp.Name = reader.GetValue(1).ToString();  
  23.         emp.ManagerId = Convert.ToInt32(reader.GetValue(2));  
  24.     }  
  25.     return emp;  
  26.     myConnection.Close();  
  27. }  
I run my application and verify that whether API is up or not. Kindly find given below image to identify this.

api

It shows API is running and ready to perform some action. Along with this I’ve Postman running along side where I paste the specific url. which meets the requirement as shown below:

normal

As soon as I click on the Send button it will go to the respective controller’s action to execute set of statements. This is the best benefit of Attribute routing -- you can set any route as per you convenient. Like in the above URl there is no action method defined still it finds the right action method.This type of URI is difficult to create using convention-based routing(traditional routing model). Although it can be done, the results don’t scale well if you have many controllers or resource types

The output will be like given image shown below:

output

The same way you would have an action which takes multi arguments than you can set the Attribute routing in such a way in below code segment. It makes it simple to understand and easily to execute.
  1. [HttpGet]  
  2. [Route("api/{employees}/{id}/{userName}")]  
  3. [ActionName("GetEmployeeByID")]  
  4. public Employee Get(int id, string userName)  
  5. {  
I run an application again and verify that whether API is up or not. Kindly find given below image to identify this.

api

It shows API is running and ready to perform some action. Along with this I have Postman running aside where I paste the specific url (http://localhost:57888/api/employees/4/SachinKalia) which meets the requirement as shown below:

api

As soon as user clicks on send button it should reach anticipated action method.

code

And the output will be like given below:

body

Attribute routing makes things easy and can create complex route in simpler way.

way

However there is a little issue which I confronted and would like to share with you. If you create route in such a way, that keeps parameter {controller} like in following route[Route("api/{controller}/{id}")]it prompts an error like “A direct route cannot use the parameter 'controller'. Specify a literal path in place of this parameter to create a route to a controller”. In simple words it should be a literal value. It throwsthe same issue if you keep parameter {action} in route.

code
code

Which may consume your potential time during development?


way

Kindly add the following line in Global.asax file to initialize object as give below:
  1. GlobalConfiguration.Configuration.EnsureInitialized();   
 If you don’t put this line in Global.asax file it throws an error as given below in screen shot.

code

Reference

Attribute Routing in ASP.NET Web API 2
 
Read more articles on ASP.NET: