Friday, 14 November 2014

Routing in ASP.NET MVC


What is Routing?


Routing is a pattern matching system that monitor the incoming request and figure out what to do with that request. At runtime, Routing engine use the Route table for matching the incoming request's URL pattern against the URL patterns defined in the Route table.


Routing in MVC

As MVC is all about creating loosely coupled applications ,most of the features in MVC compliment creating loosely coupled architecture. Routing is one such MVC feature which decouples the URL schema of the application from the rest of the application. To understand use of routing let's see how request handling was done one or two decades earlier.

In ASP.NET webforms and in previous web technologies whenever we make a browser request for a resource such as a web page, the web server expects that it exists physically on the server which it returns to the browser ,either executing it and returning the HTML (in the case of dynamic pages such as aspx pages) or as such if it’s an html page. In other words there has to be One to One mapping between the URL and the requested resource such as the web form or the html page.



Request handling in conventional Web Forms application 's



This was the normal scenario prior to the ASP.NET MVC. In ASP.NET MVC since the request is handled by action methods there has to be some way to map the URL to the appropriate action method as there is no physical file to handle the requested URL.This mapping is provided by the routing system.






Request handling in MVC applicationAll the routes used in the application are added to the RouteCollection .So routing system acts as an interface between the request and the request handler.

This means we can structure our URL according to our requirement like we can create user friendly and Search Engine Optimized URL's. Also the URL's can be changed anytime without requiring the change to the application logic since the application logic is decoupled from the URL schema used in the application.

Following is the basic structure of a requested URL as understood by the routing system.


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


Here url is the url -pattern that is used to determine if the incoming url should be handled by the route as Mvc application can have multiple routes.The segments in the url-pattern in the braces {} are called the segments variables ,like {controller},{action} and {id} .The values for these segment variables are extracted from the url.Though we have used variables here segments can also be a literal like a string.

The above route is added to the routes route collection when the application is initialized as the method is called from the Application_Start method in global.asax.

Now suppose we want to change the url-pattern that is handled by a specific action method in a controller we need to make the change in the common RegisterRoutes method.This has the following disadvantages
  • Since RegisterRoutes is the common method which define's all the routes in the application ,our change could break the url handling of the application. 
  • Since routing is setup when the application is launched we don’t have any easy way to change the routing schema of the application without effecting the existing routes in the application as we need to consider the order in which we have to add our route(as routes are evaluated from top to bottom).This requires proper testing for verifying if new bugs are introduced because of a newly added route. 
  • Also keeping the route definition separate from the controller and action methods which is the handler of the request is not much intuitive.
Attribute based routing provides an elegant way to solve this issue.

Attribute based routing in MVC 5

This is where attribute based routing comes in. Using attribute based routing we can define the route in the same place where action method is defined. Following is an example of a route defined using the Route attribute. As you can see the route is directly attached to the action method.
  [Route("Products/Electronics/{id}")]
       public ActionResult GetElectronicItems(string id)
       {
           ViewBag.Id = id;
            return View();
       }     
To enable attribute based routing we need to add the following in the RouteConfig file.
 public static void RegisterRoutes(RouteCollection routes)
        {
            routes.MapMvcAttributeRoutes();
        }  
So now we have attached the Route attribute to our action method our action method will be able to handle the requests which matches the URL pattern defined by the Route attribute.

Optional Parameter

We can also specify if there is any optional parameter in the URL pattern defined by the Route attribute with the“?” character.

If the above action method is called and and the value for “id” parameter is not provided we will get an exception since id is a required parameter. We can make it an optional parameter by making the following changes.
  [Route("Products/Electronics/{id?}")]
        public ActionResult GetElectronicItems(int? id) { 
            ViewBag.Id = id; return View(); 
        }    


Note that we have made id an optional parameter by using “?”.Also since id is a value type we have to make it nullable type since we always need to provide values for value type parameters as they cannot have null values.

Route constraints

We can also specify parameter constraints placing the constraint name after the parameter name separated by colon. For example we can specify that the parameter type should be integer by using the following
 [Route("Products/Electronics/{id:int}")] 
Now If we do not specify integer parameter then the route will not match even if other segments match. Some of the other useful constraints that we can use in Route attribute are:
Route Constraint
Used To
x:boolMatch a bool parameter
x:maxlength(n)Match a string parameter with maximum length of n characters
x:minlength(n)Match a string parameter with minimum length of n characters
x:maxMatch an integer parameter with a maximum value of n.
x:minMatch an integer parameter with a minimum value of n.
x:rangeMatch an integer parameter within a range of values.
x:floatMatch floating-point parameter.
x:alphaMatch uppercase or lowercase alphabet characters
x:regexMatch a regular expression.
x:datetime
Match a DateTime parameter.
Route Prefix


if we have multiple action methods in a controller all using the same prefix we can use RoutePrefix attribute on the controller instead of putting that prefix on every action method.

Like we can attach the following attribute on the controller
[RoutePrefix("Products")]
So now our Route attribute on our action method does not need to specify the common prefix
[Route("Electronics/{id}")]
   

Using the Default Route Table

When you create a new ASP.NET MVC application, the application is already configured to use ASP.NET Routing. ASP.NET Routing is setup in two places.

First, ASP.NET Routing is enabled in your application's Web configuration file (Web.config file).

There are four sections in the configuration file that are relevant to routing:
  • system.web.httpModules section, 
  •  system.web.httpHandlers section,
  •   system.webserver.modules section,
  •   system.webserver.handlers section.
Be careful not to delete these sections because without these sections routing will no longer work.

Second, and more importantly, a route table is created in the application's Global.asax file. The Global.asax file is a special file that contains event handlers for ASP.NET application lifecycle events. The route table is created during the Application Start event.

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

namespace MvcApplication1
{
    // Note: For instructions on enabling IIS6 or IIS7 classic mode, 
    // visit http://go.microsoft.com/?LinkId=9394801

    public class MvcApplication : System.Web.HttpApplication
    {
        public static void RegisterRoutes(RouteCollection routes)
        {
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

            routes.MapRoute(
                "Default",                                              // Route name
                "{controller}/{action}/{id}",                           // URL with parameters
                new { controller = "Home", action = "Index", id = "" }  // Parameter defaults
            );

        }

        protected void Application_Start()
        {
            RegisterRoutes(RouteTable.Routes);
        }
    }
}

No comments:

Post a Comment