Attribute Routing in ASP.NET MVC

Attribute Routing in ASP.NET MVC Application

In this article, I am going to discuss Attribute Routing in ASP.NET MVC Application with examples. This is one of the new features introduced in ASP.NET MVC 5. Please read our previous article where we discussed the Route Constraints in Conventional based Routing. As part of this article, we are going to discuss the following pointers in detail which are related to ASP.NET MVC Attribute Routing.

  1. What is Attribute Routing in MVC?
  2. Why do we need Attribute Routing in ASP.NET MVC Application?
  3. How to Enabling Attribute Routing in ASP.NET MVC Application?
  4. Examples of using Attribute Routing.
  5. What are the advantages of using Attribute Routing in MVC?
  6. Can we use both Attribute Routing and Convention-based routing in a single MVC project?
What is Attribute Routing in ASP.NET MVC?

If we are defining Routes by using the [Route] attribute is called Attribute Routing. It provides you more control over the URIs by defining routes directly on actions and controllers in your ASP.NET MVC application.

Note: The earlier style of routing, called convention-based routing, is still fully supported by ASP.NET MVC 5. In fact, you can combine both these routing approaches in the same project.

Why do we need Attribute Routing in ASP.NET MVC Application?

Let us understand the need for attribute routing in the ASP.NET MVC Application with an example. Create a new Empty ASP.NET MVC application with the name AttributeRoutingDemoInMVC. Then Right-click on the “Models” folder and add a class file with the name Student.cs and then copy and paste the following code in it.

namespace AttributeRoutingDemoInMVC.Models
{
    public class Student
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }
}
Creating Students Controller:

Right-click on the Controllers folder and then add a new ASP.NET MVC 5 Empty controller with the name StudentsController.cs and then copy and paste the following code in it.

namespace AttributeRoutingDemoInMVC.Controllers
{
    public class StudentsController : Controller
    {
        static List<Student> students = new List<Student>()
        {
            new Student() { Id = 1, Name = "Pranaya" },
            new Student() { Id = 2, Name = "Priyanka" },
            new Student() { Id = 3, Name = "Anurag" },
            new Student() { Id = 4, Name = "Sambit" }
        };

        [HttpGet]
        public ActionResult GetAllStudents()
        {
            return View(students);
        }

        [HttpGet]
        public ActionResult GetStudentByID(int studentID)
        {
            Student studentDetails = students.FirstOrDefault(s => s.Id == studentID);
            return View(studentDetails);
        }

        [HttpGet]
        public ActionResult GetStudentCourses(int studentID)
        {
            List<string> CourseList = new List<string>();

            if (studentID == 1)
                CourseList = new List<string>() { "ASP.NET", "C#.NET", "SQL Server" };
            else if (studentID == 2)
                CourseList = new List<string>() { "ASP.NET MVC", "C#.NET", "ADO.NET" };
            else if (studentID == 3)
                CourseList = new List<string>() { "ASP.NET WEB API", "C#.NET", "Entity Framework" };
            else
                CourseList = new List<string>() { "Bootstrap", "jQuery", "AngularJs" };

            ViewBag.CourseList = CourseList;

            return View();
        }
    }
}

Add the respective views for the above three action methods.

GetAllStudents.cshtml

The following view will render all the student data. The following is a strongly typed view and the model for this view is IEnumerable<AttributeRoutingDemoInMVC.Models.Student>.

@model IEnumerable<AttributeRoutingDemoInMVC.Models.Student>
@{
    ViewBag.Title = "GetAllStudents";
}
<h2>GetAllStudents</h2>
<table class="table">
    <tr>
        <th>
            @Html.DisplayNameFor(model => model.Id)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.Name)
        </th>

    </tr>

    @foreach (var item in Model)
    {
        <tr>
            <td>
                @Html.DisplayFor(modelItem => item.Id)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Name)
            </td>
        </tr>
    }

</table>
GetStudentByID.cshtml

The following view will render the data of a particular student. The following view is a strongly typed view and the model for this view is AttributeRoutingDemoInMVC.Models.Student.

@model AttributeRoutingDemoInMVC.Models.Student
@{
    ViewBag.Title = "GetStudentByID";
}
<h2>GetStudentByID</h2>
<div>
    <h4>Student</h4>
    <hr />
    <dl class="dl-horizontal">
        <dt>
            @Html.DisplayNameFor(model => model.Name)
        </dt>
        <dd>
            @Html.DisplayFor(model => model.Name)
        </dd>
        <dt>
            @Html.DisplayNameFor(model => model.Id)
        </dt>
        <dd>
            @Html.DisplayFor(model => model.Id)
        </dd>
    </dl>
</div>
GetStudentCourses.cshtml

The following view will render the courses of a particular student. The following view is not a strongly-typed view and here we are using ViewBag to fetch the courses.

@{
    ViewBag.Title = "GetStudentCourses";
}
<h2>GetStudentCourses</h2>
@foreach (var item in ViewBag.CourseList)
{
    <li>@item</li>
}

In ASP.NET MVC, we have convention-based routing that defines routes using the route templates. When we create a new ASP.NET MVC 5 Application using Visual Studio, then by default a route (i.e. default route) is created in the RouteConfig.cs class file. The default route is shown below.

namespace AttributeRoutingDemoInMVC
{
    public class RouteConfig
    {
        public static void RegisterRoutes(RouteCollection routes)
        {
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

            routes.MapRoute(
                name: "Default",
                url: "{controller}/{action}/{id}",
                defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
            );
        }
    }
}

Now we can access the above three methods using the following URL

  1. http://localhost:58316/Students/GetAllStudents
  2. http://localhost:58316/Students/GetStudentByID?studentID=1
  3. http://localhost:58316/Students/GetStudentCourses?studentID=1

In some scenarios, convention-based routing is very difficult to support certain URL patterns. But those URL patterns can be easily achieved by using the Attribute Routing in ASP.NET MVC. For example, resources often contain child resources like Clients have Ordered; Movies have Actors, and Books have Authors, and so on. It’s natural to create URIs that reflects these relations like as /clients/1/orders

In our example, If we want the URL Pattern “/students/1/courses” and if that URL Pattern should be mapped to GetStudentCourses(int studentID), then this type of URL is very difficult to create using the convention-based routing in ASP.NET MVC Application. But by using Attribute Routing which is a new feature introduced in ASP.NET MVC 5, this type of URL pattern can be achieved very easily.

How to use Attribute Routing in ASP.NET MVC?

The attribute routing can only be used with ASP.NET MVC 5, if you are using MVC 4, or lower version, you can not use Attribute Routing The first thing that you need to do is Enabling Attribute Routing in RouteConfig.cs class.

How to Enabling Attribute Routing in ASP.NET MVC Application?

Enabling the Attribute Routing in ASP.NET MVC 5 Application is very simple. You just need to add a call to routes.MapMvcAttributeRoutes() method within the RegisterRoutes() method of RouteConfig.cs file. So, open the RouteConfig.cs file which is stored within the App_Start folder, and then just adds routes.MapMvcAttributeRoutes(); method just above the routes.MapRoute method as the show is below. The Attribute routing should configure before the convention-based routing.

namespace AttributeRoutingDemoInMVC
{
    public class RouteConfig
    {
        public static void RegisterRoutes(RouteCollection routes)
        {
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

            //Enabling attribute routing 
            routes.MapMvcAttributeRoutes();

            routes.MapRoute(
                name: "Default",
                url: "{controller}/{action}/{id}",
                defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
            );
        }
    }
}

With the above changes in place, now your MVC application is going to support Attribute Routing. The next step is to decorate either the controller or action method with the Route attribute.

Using Route Attribute in ASP.NET MVC:

Modify the GetStudentCourses Action Method as shown below. As you can see, here we decorate the GetStudentCourses Action Method with [Route(“students/{studentID}/courses”)] Attribute.

[HttpGet]
[Route("students/{studentID}/courses")]
public ActionResult GetStudentCourses(int studentID)
{
    List<string> CourseList = new List<string>();

    if (studentID == 1)
        CourseList = new List<string>() { "ASP.NET", "C#.NET", "SQL Server" };
    else if (studentID == 2)
        CourseList = new List<string>() { "ASP.NET MVC", "C#.NET", "ADO.NET" };
    else if (studentID == 3)
        CourseList = new List<string>() { "ASP.NET WEB API", "C#.NET", "Entity Framework" };
    else
        CourseList = new List<string>() { "Bootstrap", "jQuery", "AngularJs" };

    ViewBag.CourseList = CourseList;

    return View();
}

With the above changes in place, you can access the above action by using students/{studentID}/courses URLHere, studentID will be replaced with the values. Now navigate to the following URL and you should get the output as expected.

http://localhost:58316/students/2/courses (You need to change the port number)

What are the advantages of using Attribute Routing in ASP.NET MVC5?
  1. It gives us more control over the URIs than convention-based routing. Creating URI patterns like hierarchies of resources (For example, students have courses, Departments have employees) is very difficult with convention-based routing.
  2. Reduces the chances for errors, if a route is modified incorrectly in RouteConfig.cs then it may affect the entire application’s routing.
  3. May decouple controller and action names from route entirely.
  4. Easy to map two routes pointing to the same action.
Can we use both Attribute Routing and Convention-based routing in a single MVC project?

Yes, both the routing mechanisms can be combined in a single ASP.NET MVC project. The controller action methods that have the [Route] attribute uses Attribute Routing, and the action methods without the [Route] attribute uses Convention-based routing.

In the next article, I am going to discuss Attribute Routing with Optional Parameterin ASP.NET MVC Application. Here in this article, I try to explain the basis of Attribute Routing in ASP.NET MVC application. I hope you enjoy this Attribute Routing in ASP.NET MVC article.