Convention Routing in ASP.NET MVC 5

Introduction

In ASP.NET MVC, when a user requests any webpage, the requested URL should match with the URL pattern defined in the RegisterRoutes method of the Route Config class. If the URL doesn't match with the pattern, then the user will be displayed with an error message.

If the user doesn't provide the action method name in the URL, then by default Index Action Method will be executed. Similarly, if the user doesn't provide Controller name and the Action Method name in the URL, then the default Controller and default Action Method will be executed.

Whenever the user creates an MVC application, by default RegisterRoutes method will come with the following code.

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

Above, the user needs to provide the URL as the Controller Name/ Action Method Name and a Parameter Value like below, localhost:40962/Employee/Details/1. To handle this request we should have Details Action Method in EmployeeController.

public ActionResult Details(int employeeId)
{
    return View();
}

If the user provides an employee ID parameter in the Details Action Method that doesn't match with the above URL pattern, the request cannot be handled with the Controller and its Action Method. Instead, we will receive an error.

Instead of using the default routing pattern, we can write our own routing. This is nothing but Convention Routing. In the below code, we have two convention routing or

user-defined routing and one default routing.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;

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

            routes.MapRoute(
                "GetEmployeeById",
                "Employee/GetEmployeeInfo/{employeeId}",
                new { Controller = "Employee", action = "GetEmployeeByEId" },
                new { employeeId = @"\d{4}" }
            );

            routes.MapRoute(
                "GetEmployeeByDeptId",
                "Employee/GetEmployeeInfoByDept/{departmentId}",
                new { controller = "Employee", action = "GetEmployeeByDId" },
                new { departmentId = @"\d{4}" }
            );

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

In the first routing, we have the default name set as "GetEmployeeById", the URL as "Employee/GetEmployeeInfo/{employeeId}", the Controller Name as Employee, Action Method as "GetEmployeeByEId" and Constraints as employeeId=@"\d{4}".

From the above Convention Routing, we have provided the URL as "Employee/GetEmployeeInfo/{employeeId}", whenever the user navigates to this URL by passing the

value then the GetEmployeeByEId Action Method is executed. Here, the GetEmployeeByEId Action Method parameter name and routing URL pattern parameter name should be the same. We have given the constraint name as employeeId which should contain 4 digits.

In the second routing, we have the default name set as "GetEmployeeByDeptId", the URL as "Employee/GetEmployeeInfoByDept/{departmentId}", Controller Name as Employee, the ActionMethod as "GetEmployeeByDId" and Constraints as departmentId = @"\d{4}".

From the above Convention Routing, we have provided the URL as "Employee/GetEmployeeInfoByDept/{departmentId}", whenever the user navigates to this URL by passing the value then the "GetEmployeeByDId" Action Method is executed. Here "GetEmployeeByDId" Action Method parameter name and the routing URL pattern parameter name should be the same. We have given constraint name as departmentId which should contain 4 digits.

If the GetEmployeeByEId / GetEmployeeByDId Action Method parameter name doesn't match with the routing URL pattern or employeeId / departmentId contains less than 4 digits, then the user will be displayed with an error message.

Convention Routing in ASP.NET MVC 5

In order to understand convention-based routing, I have created an ASP.NET MVC application.

I am using Visual Studio 2019 community edition to create a sample project, you can use any version of your choice.

Step 1. Open Visual Studio 2019 and click on Create a new project on the bottom right, as shown below:

Create project

Step 2. Search ASP.NET Web Application in the above-provided textbox and click on the template. Then, click on the Next button as shown below:

Web Application

Step 3. Provide the Project name as you wish, I have used the project name ConventionRouting. Click on the Create button.

Step 4. Select the MVC template and click on the Create button. With this, a new MVC project is Created.

Once the ASP.NET 5 Application is created, we need to Create a Model to use in our application. In this example, I will assign the object with some hardcoded values.

In order to create a Model, right-click on the Models folder then click on Add. Select the class template and give the name as Employee. cs, then click on the Add button.

With this, Employee.cs Model will be created in the Models folder.

Open the Employee. cs file and paste the properties as shown below.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Web;

namespace ConventionRouting.Models
{
    public class Employee
    {
        [DisplayName("Employee Id")]
        public int EmployeeId { get; set; }
        [DisplayName("Employee Name")]
        public string EmployeeName { get; set; }
        [DisplayName("Employee Designation")]
        public string EmployeeDesignation { get; set; }
        [DisplayName("Date Of Joining")]
        public string DateOfJoining { get; set; }
        [DisplayName("Employee Phone")]
        public int EmployeePhone { get; set; }
        [DisplayName("Employee Gender")]
        public string EmployeeGender { get; set; }
        [DisplayName("City")]
        public string City { get; set; }
        [DisplayName("Project")]
        public string Project { get; set; }
        [DisplayName("Company Name")]
        public string CompanyName { get; set; }
        [DisplayName("Department Name")]
        public string DepartmentName { get; set; }
        [DisplayName("Department Id")]
        public int DepartmentId { get; set; }
    }
}

In order to create an EmployeeController, right-click on Controller's folder, click on Add, and click on Controller, with this Add Scaffold template will be opened. In this

select MVC 5 Controller - empty and click on Add button. In the Add Controller window, give the Controller name as EmployeeController and click on the Add button. A

EmployeeController will be created in the Controllers folder.

Now open the EmployeeController.cs class file and paste the below code.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using ConventionRouting.Models;

namespace ConventionRouting.Controllers
{
    public class EmployeeController : Controller
    {
        List<Employee> listEmployee = new List<Employee>();

        // GET: Employee
        public ActionResult GetEmployeeByEId(int employeeId)
        {
            AssigningValues();
            Employee employees = (Employee)listEmployee.Where(x => x.EmployeeId == employeeId).ToList().SingleOrDefault();

            return View(employees);
        }

        public ActionResult GetEmployeeByDId(int departmentId)
        {
            AssigningValues();
            List<Employee> employeeByDept = listEmployee.Where(x => x.DepartmentId == departmentId).ToList();
            return View(employeeByDept);
        }

        public void AssigningValues()
        {
            listEmployee.Add(new Employee()
            {
                EmployeeId = 1001,
                EmployeeName = "Khaja",
                EmployeeDesignation = "SE",
                DateOfJoining = "22/05/2015",
                EmployeePhone = 806980474,
                EmployeeGender = "Male",
                City = "Hyderabad",
                Project = "AILabz",
                CompanyName = "ValueLabs",
                DepartmentName = "Testing",
                DepartmentId = 1700
            });

            listEmployee.Add(new Employee()
            {
                EmployeeId = 1002,
                EmployeeName = "Vijay",
                EmployeeDesignation = "S.SE",
                DateOfJoining = "10/05/2013",
                EmployeePhone = 907846532,
                EmployeeGender = "Male",
                City = "Hyderabad",
                Project = "AutomationTool",
                CompanyName = "Accenture",
                DepartmentName = "Quality Analyst",
                DepartmentId = 1701
            });

            listEmployee.Add(new Employee()
            {
                EmployeeId = 1003,
                EmployeeName = "Ganesh",
                EmployeeDesignation = "TeamLead",
                DateOfJoining = "01/10/2012",
                EmployeePhone = 798534120,
                EmployeeGender = "Male",
                City = "Bangalore",
                Project = "AzureDevOps",
                CompanyName = "Cognizant",
                DepartmentName = "Quality Analyst",
                DepartmentId = 1701
            });

            listEmployee.Add(new Employee()
            {
                EmployeeId = 1004,
                EmployeeName = "Pavan",
                EmployeeDesignation = "Manager",
                DateOfJoining = "01/10/2012",
                EmployeePhone = 798534120,
                EmployeeGender = "Male",
                City = "Bangalore",
                Project = "AzureDevOps",
                CompanyName = "Cognizant",
                DepartmentName = "Development",
                DepartmentId = 1702
            });
        }
    }
}

Here we have two Action Methods, GetEmployeeByEId and GetEmployeeByDId. In the first Action Method, I am filtering through a list of employees by employeeId. In the second Action Method, I am filtering a list of employees by department.

In order to Create a View for the GetEmployeeByEId Action Method, right-click on GetEmployeeByEId Action Method, click on Add View and click on Add. A GetEmployeeByEId.cshtml file will be created.

Similarly, in order to Create a View for the GetEmployeeByDId Action Method, right-click on the GetEmployeeByDId Action Method, click on Add View, and click on Add.

GetEmployeeByDId.cshtml file will be created.

Open the GetEmployeeByEId.cshtml file and paste the below code.

@model ConventionRouting.Models.Employee
@{
    ViewBag.Title = "GetEmployeeByEId";
}
<h2>GetEmployeeByEId</h2>
<hr>
<h3>Employee Information Using Convention Routing</h3>
<table>
    <tr>
        <th>@Html.DisplayNameFor(x => x.EmployeeId)</th>
        <th>@Html.DisplayNameFor(x => x.EmployeeName)</th>
        <th>@Html.DisplayNameFor(x => x.EmployeeDesignation)</th>
        <th>@Html.DisplayNameFor(x => x.DateOfJoining)</th>
        <th>@Html.DisplayNameFor(x => x.EmployeePhone)</th>
        <th>@Html.DisplayNameFor(x => x.EmployeeGender)</th>
        <th>@Html.DisplayNameFor(x => x.City)</th>
        <th>@Html.DisplayNameFor(x => x.Project)</th>
        <th>@Html.DisplayNameFor(x => x.CompanyName)</th>
        <th>@Html.DisplayNameFor(x => x.DepartmentName)</th>
        <th>@Html.DisplayNameFor(x => x.DepartmentId)</th>
    </tr>

    <tr>
        <td>@Html.DisplayFor(x => x.EmployeeId)</td>
        <td>@Html.DisplayFor(x => x.EmployeeName)</td>
        <td>@Html.DisplayFor(x => x.EmployeeDesignation)</td>
        <td>@Html.DisplayFor(x => x.DateOfJoining)</td>
        <td>@Html.DisplayFor(x => x.EmployeePhone)</td>
        <td>@Html.DisplayFor(x => x.EmployeeGender)</td>
        <td>@Html.DisplayFor(x => x.City)</td>
        <td>@Html.DisplayFor(x => x.Project)</td>
        <td>@Html.DisplayFor(x => x.CompanyName)</td>
        <td>@Html.DisplayFor(x => x.DepartmentName)</td>
        <td>@Html.DisplayFor(x => x.DepartmentId)</td>
    </tr>
</table>

<style>
    table {
        font-family: arial, sans-serif;
        border-collapse: collapse;
        width: 100%;
    }

    td, th {
        border: 1px solid #dddddd;
        text-align: left;
        padding: 4px;
    }
</style>

Open the GetEmployeeByDId.cshtml file and paste the below code.

@model IEnumerable<ConventionRouting.Models.Employee>

@{
    ViewBag.Title = "GetEmployeeByDId";
}

<h2>GetEmployeeByDId</h2>

<hr>

<h3>Employee Information Using Convention Routing</h3>

<table>
    <tr>
        <th>@Html.DisplayNameFor(x => x.EmployeeId)</th>
        <th>@Html.DisplayNameFor(x => x.EmployeeName)</th>
        <th>@Html.DisplayNameFor(x => x.EmployeeDesignation)</th>
        <th>@Html.DisplayNameFor(x => x.DateOfJoining)</th>
        <th>@Html.DisplayNameFor(x => x.EmployeePhone)</th>
        <th>@Html.DisplayNameFor(x => x.EmployeeGender)</th>
        <th>@Html.DisplayNameFor(x => x.City)</th>
        <th>@Html.DisplayNameFor(x => x.Project)</th>
        <th>@Html.DisplayNameFor(x => x.CompanyName)</th>
        <th>@Html.DisplayNameFor(x => x.DepartmentName)</th>
        <th>@Html.DisplayNameFor(x => x.DepartmentId)</th>
    </tr>
    
    @foreach (Employee employee in Model)
    {
        <tr>
            <td>@Html.DisplayFor(x => employee.EmployeeId)</td>
            <td>@Html.DisplayFor(x => employee.EmployeeName)</td>
            <td>@Html.DisplayFor(x => employee.EmployeeDesignation)</td>
            <td>@Html.DisplayFor(x => employee.DateOfJoining)</td>
            <td>@Html.DisplayFor(x => employee.EmployeePhone)</td>
            <td>@Html.DisplayFor(x => employee.EmployeeGender)</td>
            <td>@Html.DisplayFor(x => employee.City)</td>
            <td>@Html.DisplayFor(x => employee.Project)</td>
            <td>@Html.DisplayFor(x => employee.CompanyName)</td>
            <td>@Html.DisplayFor(x => employee.DepartmentName)</td>
            <td>@Html.DisplayFor(x => employee.DepartmentId)</td>
        </tr>
    }
</table>

<style>
    table {
        font-family: arial, sans-serif;
        border-collapse: collapse;
        width: 100%;
    }

    td, th {
        border: 1px solid #dddddd;
        text-align: left;
        padding: 4px;
    }
</style>

In order to execute the above code, we have two different URL's provided in RouteConfig as Convention or the user-defined routing like below.

"Employee/GetEmployeeInfo/{employeeId}",

"Employee/GetEmployeeInfoByDept/{departmentId}",

When the user requests for "Employee/GetEmployeeInfo/{1001}", then the GetEmployeeByEId Action Method of EmployeeController handles the request and returns the Employee details whose EmployeeId is 1001, similarly when a user requests for "Employee/GetEmployeeInfoByDept/{1701}", then the GetEmployeeByDId Action Method of EmployeeController handles the request and returns an Employee or a list of Employees whose departmentId is 1701.

The output for the above code is shown below.

Code

Output

Conclusion

With the above RouteConfig, the user can create his own custom routing or convention routing when they don't want to work with default routing. The drawback of convention routing is that if there are multiple requested URLs or large applications, then the user needs to add multiple convention routing in the RouteConfig class. This can become complex work. Furthermore, if the user is required to change the Action Method name, then he also needs to change the Action Method name in the RouteConfig class. In order to overcome this drawback, we will check out Attribute Routing, reviewed in our next post.

Thanks for reading my article, hope this helps you.


Similar Articles