Attribute Routing In MVC 5 ASP.Net

In MVC routing is a very appealing feature and we discussed about the traditional routing used in ealier MVC ASP.Net versions. However in this topic we will learn about Attribute Routing which is introduced with MVC 5. It is much more advanced and much more developer friendly as compared to the tradional routing technique where all the routes were mentioned in RouteConfig.cs file.





What Is Attribute Routing?


In MVC there are contollers & actions which present views to the user for interaction. To access these Views MVC use routing technique, so that application can interpret which View is to be shown for which URL. Attribute routing is different from conventional routing used earlier because in conventional routing the routes were specified away from the code in RouteConfig.cs file, but here in attribute routing the routes are declared within the code file.

In MVC the attributes are specified using the square brackets [Attribute], so here to specify a route you have to use RouteAttribute with its declaration as [Route("pattern of route to match")]. Shown below is example of AttributeRouting.

public class HomeController : Controller
{
    [Route("Home")]
    public ActionResult Index()
    {
        return View();
    }
}

Here in this snippet a route has been specified that if a user comes and enter www.xyzdomain.com/Home then user will be sent to Index view of HomeController. We will discuss about different ways in which routes can be specified but first lets see how to enable AttributeRouting through RouteConfig.cs.

How To Enable Attribute Routing?

To enable attribute routing you just have to write a single line and your routes mentioned in controller will start working. In RegisterRoutes method of RouteConffig.cs you just have to write routes.MapMvcAttributeRoutes();
Shown below is the code snippet of it.

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

You can also keep the old conventional route map in conjunction with the attribute routes if you want to.

public class RouteConfig
{
    public static void RegisterRoutes(RouteCollection routes)
    {
        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
        routes.MapMvcAttributeRoutes();
        routes.MapRoute(
            name: "Default",
            url: "{controller}/{action}/{id}",
            defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
        );
    }
}

URL Parameters In Attribute Routing


Instead of using the ugly looking querystrings, MVC gives us beautiful ways of passing parametes within URLs. Lets see examples for different parameter related scenarios.

Single Parameter


Shown below is an example of a School website where there is a controller related to Student and an action StudentInfo which serves the info related to a specific student. Above the RouteAttribute we have specified  different types of URLs which are suitable for calling this action. For all the examples refer these URLs and understand the relation between Parameters and Routes

The name of the parameter and the name of the parameter in Route should be same to exactly map the route. The name inside the curly braces {} is the parameter that is mapped with the action of controller. MVC Routing checks for these curly braces to identify the parameter value in the URL and then send that value to the action.

// Examples of suitable URLs
// /Student/1
// /Student/john.miller
// /Student/john
// /Student/john1
[Route("Student/{id}")]
public ActionResult StudentInfo(string id)
{
    //
    //Action Specific Logic...
    //
    return View();
}

Multiple Parameters


Shown below is an example for multiple parameters wherein user can enter all the values in string format. Different examples for URLS are shown below and many more combinations can also be made. name, department, year parameters are mapped with route.

// Examples of suitable URLs
// /Student/1/science/2016
// /Student/john.miller/arts/2016
// /Student/john/SC-01/2016
// /Student/john1
[Route("Student/{name}/{department}/{year}")]
public ActionResult StudentInfo(string name, string department, string year)
{
    //
    //Action Specific Logic...
    //
    return View();
}

Multiple Parameters With Different Parameter Type


Shown below is an example for multiple parameters with different data types. Here MVC routing mechanism is so smart that it will automatically adjust the values obtained from URL to the expected type of the parameter.  Like here it will automatically convert the dateofjoining value to DateTime object. Microsoft is just amazing. :)


// Examples of suitable URLs
// /Student/john/10-10-2016
// /Student/john.miller/10/31/2016
[Route("Student/{name}/{dateofjoining}")]
public ActionResult StudentInfo(string name, DateTime dateofjoining)
{
    //
    //Action Specific Logic...
    //
    return View();
}

Just in case you specify wrong input parameter to your URL which can't be converted to the expected parameter type, then the system throws an error.
For ex: if your URL for above action is
/Student/john/xyz

Since Routing mechanism can't parse xyz to DateTime, the framework throws following error

The parameters dictionary contains a null entry for parameter 'dateofjoining' of non-nullable type 'System.DateTime' for method 'System.Web.Mvc.ActionResult Index(Int32)' in 'MVCApp.Controllers.HomeController'. An optional parameter must be a reference type, a nullable type, or be declared as an optional parameter.
Parameter name: parameters

Optional Parameter


Shown below is an example for optional parameter, when the action will work in both the cases with parameter value and without parameter value in URL. This can only happen when the parameter in the route is optional. Optional parameter in Route is declared with the help of '?' question mark sign placed in the RoutingAttribute after the name of the parameter as used in below example where id is the optional parameter.


// Examples of suitable URLs
// /Student/1
// /Student
[Route("Student/{id?}")]
public ActionResult StudentInfo(string id)
{
    //
    //Action Specific Logic...
    //
    return View();
}

It will work when id has a value as well as when id doesn't have a value from URL. In case no URL has no id parameter than the action will still be hit with null as a value to id parameter.

Default Parameter


Shown below is an example for default parameter, which will work in somewhat the same way as Optional Parameter but the only difference here is that the route will have a default value in case user doesn't enter any value for id parameter. Default value for a parameter can be given just by placing '=' operator after parameter name followed by the default value you want for that parameter. Refer below example


// Examples of suitable URLs
// /Student/1
// /Student
[Route("Student/{id=1}")]
public ActionResult StudentInfo(string id)
{
    //
    //Action Specific Logic...
    //
    return View();
}

It will work when id has a value as well as when id doesn't have a value from URL. But in case nothing is passed through URL, then also id parameter will have a value of "1".

Route Contraint


If you have two actions requiring equal number of parameters but different types of parameter then we can have same route with type contraint. Refer below example where there are two actions one requires integer input while other requires string as input. So here if the URL parameter value is of integer type then first action would be hit otherwise second action.


// Examples of suitable URLs
// /Student/1
[Route("Student/{id:int}")]
public ActionResult StudentById(int id)
{
    //
    //Action Specific Logic...
    //
    return View();
}

// Examples of suitable URLs
// /Student/john
[Route("Student/{name}")]
public ActionResult StudentByName(string name)
{
    //
    //Action Specific Logic...
    //
    return View();
}


Route Prefix


If you have multiple actions and for every action you need /Student followed by parameters condition in route, then you might feel tired of writing /Student in every RouteAttribute. Fair enough, microsoft thought for it and came with RoutePrefix attribute which specifies a default preceding string that would be appended to your subsequent route. Route Prefix is mentioned for the controller, so it caters all the actions in a controller. See below example


[RoutePrefix("Student")]
public class HomeController : Controller
{
    [Route("{id:int}")]
    public ActionResult StudentById(int id)
    {
        //
        //Action Specific Logic...
        //
        return View();
    }

    [Route("{name}")]
    public ActionResult StudentByName(string name)
    {
        //
        //Action Specific Logic...
        //
        return View();
    }

    [Route("{name}/{department}")]
    public ActionResult StudentByNameDepartment(string name, string department)
    {
        //
        //Action Specific Logic...
        //
        return View();
    }
}

Here all the routes will be made after prefixing "Student" string like
/Student/id
/Student/name
/Student/name/department

However if someone wants to change the prefix for a particular action then they can use tilde '~' sign in route to override RoutePrefix. Refer below example where Student is replaced by GetStudent as RoutePrefix.


[RoutePrefix("Student")]
public class HomeController : Controller
{
    [Route("{id:int}")]
    public ActionResult StudentById(int id)
    {
        //
        //Action Specific Logic...
        //
        return View();
    }

    [Route("{name}")]
    public ActionResult StudentByName(string name)
    {
        //
        //Action Specific Logic...
        //
        return View();
    }

    [Route("~/GetStudent/{name}/{department}")]
    public ActionResult StudentByNameDepartment(string name, string department)
    {
        //
        //Action Specific Logic...
        //
        return View();
    }
}


That's all about the Attribute Routing. It's a long topic with very vast scenarios, you can hit and try different technique to achieve your desired routes.

Do let us know if this post was helpful.

Happy Learning!!!

Comments

Popular posts from this blog

Create Android Apps - Getting Started

Kotlin Type Checking and Smart Cast with Examples