Friday, June 8, 2012

MVC - Routing Concepts

MVC Routing


When we  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.
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.
Second,  In Global.asax file
 The Global.asax file is a special file that contains event handlers  application lifecycle events.
The route table is created during the Application Start event.
URLs Routes rules
 Matching a URL request to a route depends on all the following conditions:
·         The route patterns that you have defined or the default route patterns, if any, that are included in your project type.
·         The order in which you added them to the Routes collection.
·         Any default values that you have provided for a route.
·         Any constraints that you have provided for a route.
·         Whether you have defined routing to handle requests that match a physical file.


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

namespace MvcTextApplication
{
     public class MvcApplication : System.Web.HttpApplication
    {
        public static void RegisterGlobalFilters(GlobalFilterCollection filters)
        {
            filters.Add(new HandleErrorAttribute());
        }

   public static void RegisterRoutes(RouteCollection routes)
    {
      routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
      routes.MapRoute(
      "Default", // Route name
       "{controller}/{action}/{id}", // URL with parameters
       new { controller = "Emaployee", action = "ViewEmployee", id = UrlParameter.Optional } // Parameter defaults
   );


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



        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();
            RegisterGlobalFilters(GlobalFilters.Filters);
            RegisterRoutes(RouteTable.Routes);
        }
    }
}
When an MVC application first starts, the Application_Start() method is called.
This method calls the RegisterRoutes() method that creates the route table.
The default route table contains a single route (named Default). It map three segments of url , controller name , action name ,id.
In our example
In our example  OUR DEFAULT route is Emaployee /ViewEmployee   or  Emaployee / ViewEmployee  /1  where  ID  is optional parameter
Where controller = Emaployee  and Action= ViewEmployee   and  id=1


Controller :

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using MvcTextApplication.Models;
namespace MvcTextApplication.Controllers
{
    public class EmaployeeController : Controller
    {
        //
        // GET: /Emaployee/

       public ActionResult ViewEmaployee()
        {
            ViewData["CurrentTime"] = DateTime.Now.ToString();
            return View();

        }


        public ActionResult Create()
        {
            return View();
        }

        [AcceptVerbs(HttpVerbs.Post)]
        public ActionResult Create(Employee  emp)
        {
            if (!ModelState.IsValid)
            {
                return View("Create", emp);
            }
            ////people.Add(person);
            return RedirectToAction("Index");
        }
    }
}


Note : If we don’t supply Controller and  Action and ID then default  controller will be Employee  and default  action method will be  ViewEmaployee and parameter Id will be empty value.
E.g. 1  
     public ActionResult ViewEmployee()
        {
            ViewData["CurrentTime"] = DateTime.Now.ToString();
            return View();

        }


If we type url http://localhost:59829/emaployee/viewemployee then  Above method ViewEmployee() works fine because id is optional parameter and show Current date time in view

Output :  07/06/2012 11:16:47

*****************************************************

E.g. 2
      public ActionResult ViewEmployee(int id)
        {
            ViewData["CurrentTime"] = DateTime.Now.ToString() + "  Id value :" + id.ToString() ;
            return View();
        }

If we type url http://localhost:59829/emaployee/viewemployee then  Above method ViewEmployee() will give error
Because method expect parameter which is non-nullable.

If we type url http://localhost:59829/emaployee/viewemployee/1 then  Above method ViewEmployee() works fine because  we are passing parameter value and it will show output

Output :  07/06/2012 11:16:47 Id value :1

*****************************************************

E.g. 2
      public ActionResult ViewEmployee(int? id)
        {
            if (id == null)
            {
                ViewData["CurrentTime"] = DateTime.Now.ToString();
            }
            else
            {
                ViewData["CurrentTime"] = DateTime.Now.ToString() + "  Id value :" + id.ToString();
            }
            return View();
        }

If we type url http://localhost:59829/emaployee/viewemployee then Above method ViewEmployee() works fine because parameter is a nullable parameter and can have the value Null.

Output :  07/06/2012 11:16:47

If we type url http://localhost:59829/emaployee/viewemployee/1 then Above method ViewEmployee() works fine because  we are passing parameter value and it will show output

Output :  07/06/2012 11:16:47 Id value :1




Custom Route : 

We can also create custom  routes 

Example : 

HTML View
<table>
    <tr>
        <th>id</th><th>Name</th><th> Age</th> <th> email</th> <th>DOB</th>
    </tr>

<% foreach (var item in Model) { %>
    <tr>      
      <td> <%: item.Id %></td>
        <td> <%: item.Name %></td>
        <td> <%: item.Age %></td>
        <td><%: item.email %></td>
        <td>
            <%: String.Format("{0:g}", item.DOB) %>
        </td>
    </tr> 
<% } %>

</table>



Controller :

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using MvcTextApplication.Models;
namespace MvcTextApplication.Controllers
{
    public class PersonController : Controller
    {
        List<Person> people = new List<Person>();
       // GET: /Person/
        public ActionResult Index()
        {         
                Person per = new Person();
                per.Id = 1;
                per.Name = "Guugeaaa";
                per.Age = 23                per.email = "Sample@gmail.com";
                per.DOB = DateTime.Now;
                people.Add(per);
                List<Person> fundlistnew;
                fundlistnew = people;
                var movies = fundlistnew;
                return View(movies.ToList());
          
        }
   }
}



Example 1.  

Routes in Global.asax File

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


   routes.MapRoute(
   "Emaployee", // Route name
   "{controller}/{action}/{id}", // URL with parameters
   new { controller = "Emaployee", action = "ViewEmployee", id = UrlParameter.Optional } // Parameter defaults
          );



Controller method:
       
 public ActionResult Index()
        {         
                Person per = new Person();
                per.Id = 1;
                per.Name = "Guugeaaa";
                per.Age = 23                per.email = "Sample@gmail.com";
                per.DOB = DateTime.Now;
                people.Add(per);
                List<Person> fundlistnew;
                fundlistnew = people;
                var movies = fundlistnew;
                return View(movies.ToList());
          
        }

Here we didn’t supply custom route fro person Controller so if we type URL like
·         http://localhost:59829/person

Then it will show following output

Output : 

Note that in Routing table we have  one DEFAULT Route and other one is Emaployee .But IN ORDER WISE Default comes first than Employee.
In this case http://localhost:59829/person  works fine because in default route we define  pattern like "{controller}/{action}/{id}"


If we change order of routes like default become second in order then http://localhost:59829/person   will give message like the resource cannot be  found .
Example 2 :
·         Lets define Route for Controller Person

Routes in Global.asax File


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


   routes.MapRoute(
   "Emaployee", // Route name
   "{controller}/{action}/{id}", // URL with parameters
   new { controller = "Emaployee", action = "ViewEmployee", id = UrlParameter.Optional } // Parameter defaults
          );


Controller method:
         
public ActionResult Index()
        {         
                Person per = new Person();
                per.Id = 1;
                per.Name = "Guugeaaa";
                per.Age = 23                per.email = "Sample@gmail.com";
                per.DOB = DateTime.Now;
                people.Add(per);
                List<Person> fundlistnew;
                fundlistnew = people;
                var movies = fundlistnew;
                return View(movies.ToList());
          
        }

Here we  define  custom route fro person Controller so if we type URL like below all works fine and show output as expected  and shown above.

·         http://localhost:59829/person






Example 3:  

Routes in Global.asax File

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


   routes.MapRoute(
   "Emaployee", // Route name
   "{controller}/{action}/{id}", // URL with parameters
   new { controller = "Emaployee", action = "ViewEmployee", id = UrlParameter.Optional } // Parameter defaults
          );

       public ActionResult Index(int id)
        {                      
                Person per = new Person();
                per.Id = Convert.ToInt32(id); //(parameter id will be passed as Person property  ID)
                per.Name = "Guugeaaa";
                per.Age = 23;
                per.email = "Sample@gmail.com";
                per.DOB = DateTime.Now;
                people.Add(per);
                List<Person> fundlistnew;
                fundlistnew = people;
                var movies = fundlistnew;
                return View(movies.ToList());
        }

        Now let’s pass one  integer Parameter  id to our method. Now what happen
http://localhost:59829/person/index/   (it will give error We are not passing any id as parameter )
http://localhost:59829/person/index/test  (method  aspect INTEGER  value but we are passing String )   
http://localhost:59829/person  (it will give error We are not passing any id as parameter )



http://localhost:59829/person/123  (This will work Fine

 Note : that In this URL  we are not passing Action method  because  it matches with URL pattern define in Route table  "Person/{id}".


output:
 


Next  Test :  Define  constraints in Routes


      public ActionResult Index(int id)
        {
            Person per = new Person();
            per.Id = Convert.ToInt32(id); //(parameter id will be passed as Person property  ID)
            per.Name = "Guugeaaa";
            per.Age = 23;
            per.email = "Sample@gmail.com";
            per.DOB = DateTime.Now;
            people.Add(per);
            List<Person> fundlistnew;
            fundlistnew = people;
            var movies = fundlistnew;
            return View(movies.ToList());
        }

        routes.MapRoute(
           "person", // Route name
          "Person/{id}", // URL with parameters
           new { controller = "Person", action = "Index" , id=UrlParameter.Optional }//,// Parameter defaults
              , new { id = @"\d+" }
            );

http://localhost:59829/person  (output: Resource cannot be found  )
http://localhost:59829/person/test   (output: Resource cannot be found  )




Next Test  :   Pass Null  values  

       public ActionResult Index(int? id)
        {                     
                Person per = new Person();
                per.Id = Convert.ToInt32(id); //(parameter id will be passed as Person property  ID)
                per.Name = "Guugeaaa";
                per.Age = 23;
                per.email = "Sample@gmail.com";
                per.DOB = DateTime.Now;
                people.Add(per);
                List<Person> fundlistnew;
                fundlistnew = people;
                var movies = fundlistnew;
                return View(movies.ToList());
        }

http://localhost:59829/person/index/  ( This will work fine  with default value of id=0)
http://localhost:59829/person/index/Test   ( This will work fine  with string parameter  with default value of id=0)
http://localhost:59829/person/test   ( This will work fine  with string parameter  with default value of id=0)

OutPut :

 

http://localhost:59829/person  (it will show message  resource connot be found because We are not passing any id as Parameter )


Next  Test :  Define id as optional parameter in Route and Null optional parameter in Action method
      public ActionResult Index(int? id)
        {
            Person per = new Person();
            per.Id = Convert.ToInt32(id); //(parameter id will be passed as Person property  ID)
            per.Name = "Guugeaaa";
            per.Age = 23;
            per.email = "Sample@gmail.com";
            per.DOB = DateTime.Now;
            people.Add(per);
            List<Person> fundlistnew;
            fundlistnew = people;
            var movies = fundlistnew;
            return View(movies.ToList());
        }


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


OutPut :

 


Next  Test :  Define id as optional parameter in Route and Null optional parameter in Action method

      public ActionResult Index(int? id)
        {
            Person per = new Person();
            per.Id = Convert.ToInt32(id); //(parameter id will be passed as Person property  ID)
            per.Name = "Guugeaaa";
            per.Age = 23;
            per.email = "Sample@gmail.com";
            per.DOB = DateTime.Now;
            people.Add(per);
            List<Person> fundlistnew;
            fundlistnew = people;
            var movies = fundlistnew;
            return View(movies.ToList());
        }




      routes.MapRoute(
           "person", // Route name
          "Person/{id}", // URL with parameters
           new { controller = "Person", action = "Index" , id=UrlParameter.Optional }//,// Parameter defaults
              , new { id = @"\d+" }
            );


http://localhost:59829/person  (output: Resource cannot be found  )
http://localhost:59829/person/test   (output: Resource cannot be found  )


OutPut :

 
 

output


Using Static URL Segments :


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

Both methods below call Controller Home and method Index


Route with static and variable segments

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

http://localhost:59829/Home/About    (Work Fine call Controller Home and Method About)
http://localhost:59829/XHome/About (Work Fine call Controller Home and Method About)
http://localhost:59829/YHome/About (Resource cannot be found because there is no pattern defined  or controller with  name YHome)



ASP.NET MVC Routing – WildCard Parameters :

A wildcard or catch-all parameter in MVC Routing allows for a route to match a URL with an arbitrary number of parameters.
 This feature is especially useful when building CMSs, blogs etc.

routes.MapRoute(
            "Default", // Route name
             "{controller}/{action}/{*id}", // URL with parameters
            new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
           );
1.       http://localhost:59829/Home/Index/1     :  Here we are passing one argument  after Action id value  1.
2.       http://localhost:59829/Home/Index/1/23 :  Here we are passing two arguments after action so Id value will be  1/23.
Note that If we declare  pattern like  "{controller}/{action}/{id}" then second URL will message resource cannot be found.


Routing  Constraints :  

MVC Routing Constraints allow for the application of a regular expression to a URL segment to determine if the route will match the request.we define constraint here for Id parameter that id should  be integer value.

    routes.MapRoute(
           "person", // Route name
          "Person/{id}", // URL with parameters
           new { controller = "Person", action = "Index" , id=UrlParameter.Optional }//,// Parameter defaults
              , new { id = @"\d+" }
            );

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


Note the order of the definitions. ASP.NET MVC Routing attempts to match route definitions in sequence and once a match is made it is processed. Therefore, routes which contain constraints should always be placed before the simple non-constrained route definitions.



1 comment :