Today we will have a look at one of the new features introduced in ASP.NET MVC 5, attribute based routing.
Pre-Context
We all know that ASP.NET MVC is a great platform that allows us to create and manage web applications in a much simpler manner compared to form-based web applications. There are a few things in MVC based web applications that works a little differently than standard web applications, one of them is routing.
Until now, there has been a routing table that you can define either in the Global.asax or in the RouteConfig.cs and all incoming requests would look it up to decide the rendering of a target view.
Here is the code that you might have seen previously to have note-variable routes in MVC 4 in the following example of the Route collection object.
- routes.MapRoute(
- name: "Default",
- url: "{controller}/{action}/{id}",
- defaults: new { controller = "Product", action = "List", id = UrlParameter.Optional }
- );
The big question: what is the need for this new routing methodology?
And the answer is: there was nothing really wrong with the previous approach of routing and in fact you can still use it in MVC 5 or use this new routing method in conjunction with the old one.
Here are a few advantages of attribute based routing:
- Helps developer in the debugging / troubleshooting mode by providing information about routes.
- Reduces the chances for errors, if a route is modified incorrectly in RouteConfig.cs then it may affect the entire application's routing.
- May decouple controller and action names from route entirely.
- Easy to map two routes pointing to the same action.
All right, enough of talking. Let's see exactly how we can configure it and see it working.
First, we will need to enable attribute based routing on our MVC web application that can be done by only one line. All you need to do is put this line in the RegisterRoutes Method of the application.
- public static void RegisterRoutes(RouteCollection routes)
- {
- routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
-
- tes.MapMvcAttributeRoutes();
-
- routes.MapRoute(
- name: "Default",
- url: "{controller}/{action}/{id}",
- defaults: new { controller = "Product", action = "List", id = UrlParameter.Optional }
- );
-
-
- }
Now, here is how you can use the attribute based routing on a specific action method.
- [Route("products/{id?}")]
- public ActionResult Details(string id)
- {
- if (string.IsNullOrEmpty(id))
- {
- return View("List", GetProductList());
- }
-
- return View("Details", GetProductDetails());
- }
As shown in the method above, the Route is defined on a Details action method that lets users access the product details page either by of these paths:
You might have observed the question mark in the route above, all it indicates is that the id is an optional parameter of the route and hence the action method logic checks if the id is null. It will show you the product listing page.
Route Prefixes
Route Prefixes are nothing but the prefix for any route that we want to apply, all we need to do is to define the route prefix on a controller so that all the action methods inside it can follow the prefix.
For example:
- [RoutePrefix("products")]
- public class ProductController : Controller
- {
-
-
- [Route]
- public ActionResult List()
- {
- return View();
- }
-
-
-
- [Route("{id?}")]
- public ActionResult Details(string id)
- {
- if (string.IsNullOrEmpty(id))
- {
- return View("List");
- }
-
- return View("Details");
- }
- }
Route Constraints
Route constraints are nothing but a set of rules that you can define on your routing model / parameters that users need to follow when accessing the defined routes.
The way to define a constraint is by using the ":" character, let's have a look at the example below.
For example:
-
- [Route("products/{id:alpha}")]
- public ActionResult GetProduct(string name)
- {
- return View();
- }
-
-
- [Route("products/{id:int}")]
- public ActionResult GetProduct(int id)
- {
- return View();
- }
Now you might have observed in the example above that though the method name is the same the route's parameter has some constraint on it. In other words the first method will be called if the route is accessed with a string as parameter and the second method will be called if the route is accessed with an integer in the route parameter.
You can also define your custom route constraints using an IRouteConstraint interface.
Route Areas
A Route area is nothing but the way to specify the area in a route, basically just to let the route know that the controller belongs to some area.
- [RouteArea("business")]
- [RoutePrefix("products")]
- public class ProductController : Controller
- {
-
-
- [Route]
- public ActionResult List()
- {
- return View();
- }
- }