How To Define Attribute Routing

Look at this code, we’ve currently only 1 custom route if we’re working with larger application this file will grow with lots of custom routes and over the period of time it will become a huge problem for us to handle all the routes. As we can see, each route consists of 3-4 lines of code, it is so much time consuming and hard to keep in mind for logic building.

Now let’s discuss how to define the custom route in a cleaner way.

Look at this code. We currently have only one custom route, and if we’re working with larger applications this file will grow with lots of custom routes and over a period of time it will become a huge problem for us to handle all the routes. As we can see, each route consists of 3-4 lines of code, it is so time consuming and hard to keep in mind for logic building.

  1. public static void RegisterRoutes(RouteCollection routes)  
  2. {  
  3.     routes.IgnoreRoute("{resource}.axd/{*pathInfo}");  
  4.    
  5.     routes.MapRoute(  
  6.         "StudentsByNamesAndDOB",  
  7.         "students/search/{name}/{year}",  
  8.         new { controller = "Students", action = "Index" });  
  9.    
  10.    
  11.     routes.MapRoute(  
  12.         name: "Default",  
  13.         url: "{controller}/{action}/{id}",  
  14.         defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }  
  15.     );  
  16. }  

Another issue with this approach is you need to move back and forth in the files like controller and RouteConfig to verify that the pattern you’re writing in your custom route will really works. You need to make sure the action name of the action.

And the third issue is if you go back to the studentscontroller and rename the action Index to Welcome then you need to keep in your mind that you’ll also update its relevant route.

  1. new { controller = "Students", action = "Welcome" }  

So this code is fragile because of the magic strings.

In ASP.Net MVC 5, Microsoft has introduced a cleaner and better way to create the custom route. Instead of creating the route here, we can apply it using the attribute to the corresponding action. You might be thinking, then why learn an old and poor way of custom route? It's because you may be working with the existing code base with convention based custom routes so you need to understand how they work. But if you’re building a new application or improving an existing one, I would recommend you to use attribute routing.

Now let me show you how to define the custom route using an attribute.

First of all in order to use the attribute routing, you need to enable it here,

  1. public static void RegisterRoutes(RouteCollection routes)  
  2. {  
  3.     routes.IgnoreRoute("{resource}.axd/{*pathInfo}");  
  4.    
  5.     routes.MapMvcAttributeRoutes();     // enabling  
  6.    
  7.     routes.MapRoute(  
  8.         name: "Default",  
  9.         url: "{controller}/{action}/{id}",  
  10.         defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }  
  11.     );  
  12. }  

Now back to the controller.

  1. [Route("students/search/{name}/{year}")]  
  2. public ActionResult Index(string name, int year)  
  3. {  
  4.     var student = new Student  
  5.     {  
  6.         Name = "Usama",  
  7.         DOB = new DateTime(1900, 10, 25)  
  8.     };  
  9.     return View(student);  
  10. }  

Now if we want to apply the constraints here by month:

  1. [Route("students/search/{name}/{year:regex(\\d{2})}")]  
  2. public ActionResult Index(string name, int year)  
  3. {  
  4.     var student = new Student  
  5.     {  
  6.         Name = "Usama",  
  7.         DOB = new DateTime(1900, 10, 25)  
  8.     };  
  9.     return View(student);  
  10. }  

We can also apply more than one constraint on one item.

  1. [Route("students/search/{name}/{year:regex(\\d{2}):range(1, 20)}")]  
  2. public ActionResult Index(string name, int year)  
  3. {  
  4.     var student = new Student  
  5.     {  
  6.         Name = "Usama",  
  7.         DOB = new DateTime(1900, 10, 25)  
  8.     };  
  9.     return View(student);  
  10. }  

So you see attribute routes are more powerful  and we also have a bunch of other constraints as well like min, max, minlength, maxlength, int, range, float, guid etc.

You don’t have to memorize any of these constraints just be aware that they are supported by the framework and whenever you need to know about their usage, just Google the things and you’ll find the result.

We can define the attribute routes at controller level as well. Actually we define the RoutePrefix which comes before the action route in the url.

  1. [RoutePrefix("candidate")]  
  2. public class StudentsController : Controller  
  3. {  
  4.     // GET: Students  
  5.     [Route("search/{name}/{year:regex(\\d{2}):range(1, 20)}")]  
  6.     public ActionResult Index(string name, int year)  
  7.     {  
  8.         var student = new Student  
  9.         {  
  10.             Name = "Usama",  
  11.             DOB = new DateTime(1900, 10, 25)  
  12.         };  
  13.         return View(student);  
  14.     }  
  15. }  

And now this ‘Index’ action will be accessible by this kind of route

http://localhost:64341/candidate/search/usama/15

Anyhow you can explore attribute routing in detail here.

Conclusion

As we can see attribute routing is so easy to implement and learn. We don't face any kind of difficulty to move back and forth in different files for the pattern. We don’t need to take care of the rules like we do in RouteConfig.cs. That route should be defined from the most specific to more generic. Here we need to just use the attributes on the top of the action and controller. Attribute routing provides us flexibility. And it is my kind suggestion that you must read out this article.

So if you’re working on a new project then it would be a better approach to define the attribute routes because conventional routing needs more effort and code.