ASP.Net MVC 3 - An Overview Part 2
In Part1 I have given a brief introduction about ASP.Net MVC,Journey of ASP.Net MVC,important part of ASP.Net MVC 3,Request Processing cycle etc.
In Part 2 let us try to dig a bit deeper inside ASP.Net MVC like how it is taking leverage of ASP.Net routing mechanism,creation of route objects,action methods,action results,action filters,custom filters,route constraints etc.
What is routing ?
Before coming to the routing concept, let me take your attention to a classic Web application URL.
http://localhost:8080/SampleApp/Login.aspx
Here the Url points to a physical file in SampeApp folder that exists on the Web Sever disk.so we can say there exists a direct relationship between the URL and what physically resides on the desk.
Now we look to a URL of a ASP.Net MVC 3 application.
http://localhost:2587/Product/Details
Can you guess what it refers? As you can see the URL doesn't point to a physical file this time. Instead the URL point to the action method 'Detail' under the Controller 'Product'.
The reason is obvious because in ASP.Net MVC requests are handled by controller classes.
Let us see another URL which points to different action method within the same controller.
http://localhost:2587/Product/GetProduct/5
From the above URL's we can see that direct 1:1 relationship between the URL's and files won't work with ASP.Net MVC. But we can say ASP.Net MVC 3 gives us more control over how URL's are mapped to controllers.Also we can create our URL in human readable and SEO friendly manner.
To handle MVC URL's ASP.Net Platform uses a technique called Routing. Routing serves 2 main purposes.
1. It examines the incoming request and maps the request to an appropriate Controller action.
2. It generate an outcoming URL.
The routing system used by MVC 3 framework resides in System.Web Assembly . Thus routing system can be used by ASP.Net Web forms as well. More over when ever we create a ASP.Net MVC application, Visual Studio will add a reference to System.Web.Routing Assembly automatically.
What is a Route ?
Does it same as routing ?
Routing is a technique by which the incoming URL are mapped to a specific controller's action method.They are not the same.
Have you ever think, once ASP.Net MVC application got a request how it knows it has to map to an action method of a particular controller?
Here comes the importance of route.We can say route is the core object in routing.Here route refers to the URL pattern. Every MVC application must have atleast one route for handling the application request. We can define our own URL pattern in ASP.Net MVC where we should specify the pattern that the route will match.
In the route we can even specify default values also. We will come to this topic later. How to setup route in ASP.Net MVC application ?
Whenever we create an ASP.Net application by default routing is configured in 2 places.
1. In Web.Config file, routing can be enabled in the following 4 sections.
System.web.httpModules
System.web.httpHandlers
System.webserver.modules
System.websever.handlers
2. A route table is created in the application's Global.asax file during Application_Start event.ie; at first time we request a page itself.
Please have a look in to the Global.asax file
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 = "Employee", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
}
protected void Application_Start()
{
RegisterRoutes(RouteTable.Routes);
}
}
As you know, Application_Start is the first event fires once it receives a request. In the Application_Start() method, you can see a method named RegisterRoutes() which creates a route table.
As it name implies it registers the routes. All the routes for the application are registered in this method.
Let us look into this method what it says.First line tell us that any request that matches an ignoreroute will be ignored by the routing mechanism.Here all files that ends with .axd extension are ignored.The .axd files are HttpHandler files which are geneated at runtime. Since they are virtual files we don't want our routing engine to try to map these request to controllers.Also routing ignores request to any physical files by default.
Second line specifies the route. Here first parameter of MapRoute method is Default which refers to the route name.
The second parameter specifies the default route definition.
ie; {controller}/{action}/{id} . Here first part of the route definition map to the controller name, second part refers to the controller action method and third part refers to a parameter named 'id' to the action method.
The third parameter specifies default values.The default route includes default values for all the 3 section in the above route definition.The default values are used when the URL does not find a segment that can be matched to a value.
We can define our own routes.But the order of the parameters in the route definition is significant.We can define simplest Maproute method as follows.
routes.MapRoute("Default","{controller}/{action}/{id}");
Here name of the route is not mandatory but it helps to avoid ambiguities if any.
Once a request comes to ASP.Net MVC application every entry in the route collection is matched and only first matching entry is picked. Controller in depth
Now it is time to dig a bit deep into different parts of ASP.Net MVC. First we will look in to the controller. We already know about Action method of a controller which is the core part of routing.There are several other important terms in the context of controller.We will see them one by one.
Route Constraints
Constraining a route allows more control over the URL instead of specifying the number of segments.Using route constraint we can even specify regular expression to URL segments. Let us consider one example where routing constraints will be useful.
http://localhost:2587/1111/222/3
In the above URL,it contains 3 segments hence it matches the default route. So it may look for a controller named '1111' which has a method called '222' ....right ? and it provides an error since we don't have any such controller named 1111.
Let us take one more example.
http://localhost:2587/Product/GetProduct/laptop
Here it will look for a controller named 'Product' which has an action method 'GetProduct' which expects a parameter laptop.But what will happen if defined our parameter as type 'int' in the action method 'GetProduct'? It
will throw an error since it expect int parameter but we have passed string parameter.
Here comes the importance of constraints. Using constraints,regular expression can be applied to default values segments like the following example.
Example:
routes.MapRoute("Test","{controller}/{action}/{id}",new{controller = "~P*"});
In the above example, I have defined route constraint with a regular expression where it will look only for those controllers which begins with P. Using the routing constraint the above said error can be avoided. Default values are always checked before constraints are allowed.
What is an ActionResult ?
Let us consider the simple controller class.
public class ProductController: Controller {
public ActionResult index(){
return View();
}
}
Here ProductionController has an action method index which will return ActionResult object.They are different types of ActionResult that a controller can return.But the baseclass for all action results is ActionResult class. It is an Abstact class. As said,various types of ActionResult can be derived from ActionResult Class.
In ASP.Net MVC, by default all contollers will return ActionResult. Different types of action result available in ASP.Net MVC are :
1. ContentResult : Retuns a string literal.
2. FileStreamResult : Retuns a stream to the response.
3. EmptyResult : Returns a null or empty response.
4. FilePathResult : Returns the content of a file based on file path.
5. FileContentResult : Returns the content of a file.
6. JsonResult : Returns data in Json format.
7. JavaScriptResult : Returns javascript to execute on the client.
8. RedirectResult : Redirects the user to the given URL.
9. RediectToRouteResult : Redirects the user to a URL given via Routing parameters.
10.ViewResult : Render a View to the response.
11.PartialViewResult : Similar to ViewResult, except it renders a partial View to the response, typically in in response to an AJAX request.
12.HttpUnauthorizedResult : Returns HTTP 403 status.
As you know, ASP.Net MVC framework does not work with response object instead actionresult is what a controller action returns in response to a browser request. Action method can return any object type such as string ,integer ,boolean etc. provided these retun types must be wrapped in an appropriate action result type before they are rendered to the resonse team.
Examples:
We can use Content Result to return a string as follows.
public class ProductController: Controller {
public Actionesult index(){
return Content("Using ContentResult");
}
}
We can use RedirectToAction to redirect to another action in the specified Controller as folloes.
public class ProductController: Controller {
public Actionesult index(){
return RedirectToAction("ShowDetails","Order");
}
}
here Order is the Controller and ShowDetails is the ActionMethod.
The following example will return a file in response to controller action.
public class ProductController: Controller {
public Actionesult index(){
return File("MVC demo.pdf", "application/pdf");
}
}
If the file you wish to transfer file with in a disk, use the FilePathResult object. If your file is available in the form of stream you can use FileStreamResult and if the file is available as bytes use FileContentResult. FilePathResult,FileStreamResult and FileContentResult are derived from FileResult class and they differ from one another only in the way that they write out data to the response stream.
The following example will return data in Json format in response to controller action.
public class ProductController: Controller {
public Actionesult index(){
return Json("Return data in Json Format", JsonRequestBehavior.AllowGet);
}
}
What is an Action Filter ?
In ASP.Net MVC action filter refers to a custom attribute class. This attribute can be applied to a specific controller action,or to an entire controller or global level.In ASP.Net MVC 3 framework, we have following 4 types of action filters.
1. Action Filter : This filter implements IActionFilter interface and runs before and after an action. We can use this filter if we wants to add additional value to the action method or inspecting the return value of an action result etc.
2. Authorization Filter : This filter implements IAuthorizationFilter interface and it runs first before any other filters or the action methods. Using this we can dedide whether to execute an action methor or not.
3. Result Filter : This filter implements IResultFilter interface and runs before and after the action method result is executed. Using this we can perform any additional processing on the result if any.
4. Exception Filter : This filter implements IExceptionFilter interface and runs only if another action method or action result or any action filter throw an exception.In short,these filters are executed whenever an unhandled exception occurs during ASP.Net MVC lifecycle.
With the help of action filter we can inject some extra logic during the request processing life cycle. We can even create our own custom filter. Some of the action filters provided by ASP.Net MVC 3 are :
1. Authorize : It is an example for for authorization filter type which will restricts access to a patricular user or role.
2. HandleEror : It is an example for exception filter type which will handle any errors raised during a controller action.
3. OutputCache :It is an example for result filter type which will caches the output of a controller action for a specified amount of time.
4. ValidateInput :It will turn off request validation.
5. ValidateAntiForgery :It helps to prevent cross site request forgeries.
i) Applying Action Filter at Controller Level
[HandleError]
public class ProductController : Controller
{
public ActionResult About()
{
return View();
}
public ActionResult Index()
{
var plist = new List
plist.Add(new Product{ ProductId=101, ProductName="LapTop", Category="Electronics"});
plist.Add(new Product { ProductId = 102, ProductName = "Samsung Galaxy", Category = "Phone" });
plist.Add(new Product { ProductId = 103, ProductName = "TV", Category = "HouseHold" });
return View(plist);
}
}
In the above example HandleError attribute applies all action methods inside ProductController. ii)Applying Action Filter to an Action method
public class ProductController : Controller
{
[Authorize]
public ActionResult About()
{
return View();
}
[OutputCache(Duration=10)]
public string Index()
{
return DateTime.Now.ToString("T");
}
public ActionResult Show()
{
return View();
}
}
In the above example Authorize attribute apply to only the action method About.This filter ensures that this action method can only be accessed by authenticated users.
As I said earlier an Action Filter can also applied Application level which indicates that it can apply to every single request. The global filter is configured in the Global.asax file in the Application_Start() method. iii) Applying Action Filter at Application Level
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 = "Employee", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
}
protected void Application_Start()
{
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
}
}
From the above snapshot of Global.asax file, you can observe the global filter is configured in the Application_Start() method using RegisterGlobalFilters(GlobalFilters.Filters) method. As you can see this method already has HandleError attribute configured which applies to all requests.
Before invoking any action method,the ASP.Net MVC 3 will first check the method definition to see if it has any filter attributes.If any exists, filters runs in the given order.
1. Authorization Filter
2. Action Filter
3. Result Filter
4. Exception Filter
Custom Filters
As I mentioned earlier we can create custom filters too. You can do it by creating a class which should inherit from ActionFilter attribute class which in turn is inherited from Filter class and implements IActionFilter and IResultFilter interfaces.
Action filter base class has following important methods:
1. OnActionExecuting
2. OnActionExecuted
3. OnResultExecuting
4. OnResultExecuted
So in order to create custom filter we need to implement these methods. We will see an example of creating a Custom Filter in the upcoming session.
Really a good article.
I have one query : Do we really need to define many Routes in Config file for many pages or actions?
I mean, isn't it any way we will go an use only one Route for all our pages