First Look at ASP.NET MVC

What is ASP.NET MVC?

ASP.NET MVC is a framework for building scalable, standards-based web applications using well-established design patterns and the power of ASP.NET and the .NET Framework.
It is one of the best framework in the market that employs Model-View-Controller pattern to create web applications in highly modular way.
It couples the models, views, and controllers using interface-based contracts, thereby allowing each component to be easily tested independently.
The first stable version was released on March 2009 and the current stable version is 3.0 released on January 2011.
The source code is released open to public under the Apache License 2.0 and is available in codeplex.

MVC

MVC is a design architecture that helps to build a software system by separating the business model from the presentation.
MVC split the application implementation into three parts: Model, View and Controller.

Model

The domain objects in the application that maintains all the state, validations and rules associated with the business forms the Model.

View

The elements that displays the model to the user is called as a View. View is usually a HTML page.

Controller

The Controller is the component that receives input from the View and updates the Model.
It also feeds the View with the Model data to present to the user.

Benefits of ASP.NET MVC

Separation of concerns

The busines model is separated from the displaying logic, this helps to create modular systems that are easy to test and maintain.
The mantra is.. Dump Views Thin Controllers Fat Models

Enables Test Driven Development

The core components of the applications is loosely coupled through interfaces making each component testable independently.

Easy integration with JavaScript frameworks

Generates clean HTML making the application to integrate easily with popular JavaScript frameworks.

SEO friendly URLs

The Routing System helps to create simple and friendly URLs that are easily crawled by search engines and memorizable by an user.

Full control over HTML

We can generate standard-compliant HTML that helps to reach the application to a wide range of devices and browsers.

Highly extensible

We can bend the framework to our application needs, because most of the parts in ASP.NET MVC processing pipeline can be replaceable with custom components.

Benefits of ASP.NET MVC

Separation of concerns
Enables Test Driven Development
Easy integration with JavaScript frameworks
SEO friendly URLs
Full control over HTML
Highly extensible

Components of ASP.NET MVC

Controllers

Controllers

All the controllers derives from the abstract class Controller.
All the controllers should be placed in a separate folder Controllers.
MVC requires the name of all controllers to end with "Controller".
Each controller contain one or more actions that recieves and processes the HTTP requests.

A Sample Controller

	
	public class BlogController: Controller
	{
		public ActionResult Index() {
			var posts = repo.GetAllPosts();
			return View(posts);
		}
		
		public ActionResult Edit(int postId) {
			var post = repo.GetPost(postId);
			return View(post);
		}
		
		[HttpPost]
		public ActionResult Edit(Post post) {
			repo.SavePost(post);
			RedirectToAction("Index"); 
		}
	}
		

Actions and Action Results

Actions and Action Results

Action are methods inside controllers that have typically a one-to-one mapping with user interactions.
Action methods return an instance of a class that derives from ActionResult.
Some of the built-in action result types are: ContentResult, ViewResult, RedirectToRouteResult, JsonResult, FileResult etc. ViewResult returns a view from action. JsonResult returns json.
We can implement our own action results from the abstract class ActionResult.

Returning different results from actions

	
	public class HomeController: Controller
	{
		// returning a plain text from action
		public ContentResult SayHello() {
			return Content("Hello, World!");
		}
		
		// returning a view from action
		public ViewResult About() {
			return View("AboutMe");
		}
		
		// returning json from action
		public JsonResult About() {
			return Json(new { id = 1, success = true });
		}
	}
		

Views

Views

Views are templates that renders HTML output from the model data passed by the controllers.
All the views are placed in the Views folder in ASP.NET MVC.
ASP.NET MVC also contains partial, layout and error views.
Model or data from controllers are passed to views using ViewData, ViewBag.

A Sample Razor View

	
	// strongly typed razor view that dispays a html form
	@model CustomValidation.MVC.Models.Party
	@{
	  ViewBag.Title = "Party Planner";
	}
	<h2>
	  @ViewBag.Title</h2>

	@using (Html.BeginForm())
	{
	  @Html.ValidationSummary()
	  <p>
		Start date (MM/dd/yyyy HH:mm:ss AM/PM) *: 
		@Html.TextBoxFor(x => x.StartDate, new { size = 25 })</p>
	  <p>
		No. of joinees *: @Html.TextBoxFor(x => x.NoOfJoinees, new { size = 5 })</p>
	  <p>
		Drinks? @Html.CheckBoxFor(x => x.Drinks)</p>
	  <p>
		<input type="submit" value="Host the party!" />
	  </p>
	}
		

Passing data to Views

	
	// passing data to a strongly typed view from action.
	public ActionResult Index() {
		var posts = repo.GetAllPosts();
		return View(posts);
	}
	
	// passing data to view using ViewData.
	public ActionResult Index() {
		ViewData["posts"] = repo.GetAllPosts();
		return View();
	}
	
	// passing data to view using ViewBag dynamic object.
	public ActionResult Index() {
		ViewBag.Posts = repo.GetAllPosts();
		return View();
	}
		

View Engines

View Engines

The component that generates HTML output from the view and model is called as View Engine.
WebForms and Razor are the built-in view engines.
We can use multiple view engines or even use own view engine in an application.
ViewEngies are added in the Application_Start event of Global.asax.cs.
		
	ViewEngines.Engines.Add(new RazorViewEngine());
	
	ViewEngines.Engines.Add(new MyViewEngine());
		

Routing System

Routing System

The Routing system contains a set of routes that map URLs of any pattern to controller actions.
It also helps in generating outgoing URLs from the created routes.
Routes are added in the Application_Start event of Global.asax.cs.
		
	routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
	
	routes.MapRoute(
		"Post",	
		"Blog/Archive/{year}/{month}/{fileName}", 
		new { controller = "Blog", action = "Post" }
	); 
		

Filters

Filters

Fiters are used to perform logic either before an action method is called or after an action method runs.
Filters are attributes that can be applied over a controller or action or even at a global level.
The four types of filters are: Authorization, Action, Result and Exception filters.
		
	[HandleError]
	public class HomeController : Controller {
		public ActionResult About()	{
			return View();
		}
	}
		

Model Binders

Model Binders

Model Binders provides a simple way to map posted form values to a .NET Framework type and pass the type to an action method as a parameter
Model Binders are like type converters, because they can convert HTTP requests into objects that are passed to an action method.
		
	// the person instance is automatically created and populated from the values
	// available in the HTTP request.
	public ActionResult Details(Person person) {
		return View(person);
	}
		

Data Annotations

Data Annotations

Validations are easily applied to a model using data annotation attributes.
We can create our own custom validations by implementing ValidationAttribute or IValidatabaleObject.
		
	public class Movie {
		public int Id { get; set; }

		[Required(ErrorMessage="Movie title is required.")]
		[StringLength(8, ErrorMessage="Movie title cannot be longer than 8 characters")]
		public string Title { get; set; }

		[Required(ErrorMessage="Movie director is required")]
		public string Director { get; set; }
	}
		

Request-Handling Pipeline

Request-Handling Pipeline

MVC Extensions

Route Constraints

Route Constraints are applied to run some logic when the input request is received by a route.
We can create our own custom route constraints by implementing the IRouteConstraint interface.
Route Constraints are applied while creating the routes.

Creating a custom route constraint

	
	// creating a custom route constraint that matches the request to the route
	// only if it has come from a particular browser.
	public class UserAgentConstraint: IRouteConstraint {
		private string requiredUserAgent;
		
		public UserAgentConstraint(string agentParam) {
			requiredUserAgent = agentParam;
		}
		
		public bool Match(HttpContextBase httpContext, Route route, string parameterName,
			RouteValueDictionary values, RouteDirection routeDirection)	{
			return httpContext.Request.UserAgent.Contains(requiredUserAgent);
		}
	}
	
	// this route will receive only the requests that are sent by the Internet Explorer.
	routes.MapRoute("MyRoute", 
		"{controller}/{action}",
		new { controller = "Home", action = "Index" },  
		new { customConstraint = new UserAgentConstraint("IE")},
	);
		

Route Handlers

Route handler is the component that handles the request when they are matched by a route.
MvcRouteHandler is the built-in handler. We can create custom handler by implementing the IRouteHandler interface.
When we create a route we can set the route handler to handle the request.

Creating a custom route handler

	// creating a custom route handler
	public class CustomRouteHandler: IRouteHandler {
		public IHttpHandler GetHttpHandler(RequestContext requestContext) {
			return new CustomHttpHandler();
		}
	}
	
	public class CustomHttpHandler: IHttpHandler {
		public bool IsReusable {
			get{ return false; }
		}
		
		public void ProcessRequest(HttpContext context) {
			context.Response.Write("Hello");
		}
	}
	
	// setting the custom handler for a route
	routes.Add(new Route("SayHello", new CustomRouteHandler()));
		

Controller Factories

This the component that instantiate and serve controller instances to process the request.
DeafultControllerFactory is the built-in factory class.
We can create our own factory to change the controller instantiation behavior by implementing the interface IControllerFactory.
The custom controller factory are set to the MVC framework using the ControllerBuilder class in Global.asax.cs.
One of the reason we go for creating custom controller factory is for Dependency Injection.

Creating a custom controller factory

	// creating a custom controller factory that instantiates HomeController
	// without using the default constructor
	public class CustomControllerFactory: IControllerFactory {
		public IController CreateController(RequestContext requestContext,
									string controllerName) {
			return new HomeController(new PostRepository());
		}
		
		public SessionStateBehavior GetControllerSessionBehavior
			(RequestContext requestContext, strong ControllerName) {
			return SessionStateBehavior.Default;
		}
		
		public void ReleaseController(IController controller) {
			if(controller is IDisposable)
				((IDisposable)controller).Dispose();
		}
	}
	
	// setting the custom controller factory in the Application_Start event			
	ControllerBuilder.Current.SetControllerFactory(new CustomControllerFactory());
		

Action Invokers

Action Invokers are the component that invokes the action methods of a controller.
ControllerActionInvoker is the default built-in action invoker and it invokes the actions based upon the name.
Custom action invokers can be created by implementing the interface IActionInvoker.
To use our custom action invoker by the framework, we have to set it to the controller.

Creating a custom action Invoker

	// creating a custom action invoker
	public class CustomActionInvoker: IActionInvoker {
		public bool InvokeAction(ControllerContext context, string actionName) {
			if(actionName == "Index") {
				context.HttpContext.Response.Write("This is Index action");
				return true;
			}
			
			return false;
		}
	}
	
	// setting the custom action invoker to the controller
	public class CustomController: Controller {
		public CustomController() {			
			this.ActionInvoker = new CustomActionInvoker();
		}
	}
		

View Engines

ASP.NET MVC comes with two built-in view engines: Razor and WebForms.
All the view engines are implemented from the interface IViewEngine.
MVC comes with some abstract implementations of IViewEngine like VirtualPathProviderViewEngine, BuildManagerViewEngine.
All the existing and new view engines are stored in the ViewEngines collection.

Creating a custom view engine

	// a custom view engine that uses XSLTs for generating HTML from the model
	public class XsltViewEngine: VirtualPathProviderViewEngine	{
		public XsltViewEngine()	{
			base.ViewLocationFormats = new[] { "~/Views/{1}/{0}.xsl", "~/Views/Shared/{0}.xsl" };
			base.PartialViewLocationFormats = base.ViewLocationFormats;
		}

		protected override IView CreatePartialView(ControllerContext controllerContext, string partialPath)	{
			return new XsltView(partialPath);
		}

		protected override IView CreateView(ControllerContext controllerContext, string viewPath, string masterPath) {
			return new XsltView(viewPath);
		}
	}
		

Creating a custom view

	// the custom view used by the XSLT view engine.
	public class XsltView : IView {
		private readonly string _path;

		public XsltView(string path) {
			_path = path;
		}

		public void Render(ViewContext viewContext, TextWriter writer) {
			var xsltFile = viewContext.HttpContext.Server.MapPath(_path);
			var xmlData = viewContext.ViewData["data"] != null 
					? ((XElement)viewContext.ViewData["data"]).ToString() : "";

			var xmlTree = XDocument.Parse(xmlData);
			var xslt = new XslCompiledTransform();

			xslt.Load(xsltFile);
			xslt.Transform(xmlTree.CreateReader(), null, writer);
		}
	}		
		

Adding the custom view engine

View engines are added to the ViewEngines collection from the Application_Start event of Global.asax.cs.
    protected void Application_Start() {
		ViewEngines.Engines.Add(new XsltViewEngine());
	}
		

Filters

Filters inject extra logic into the request processing pipeline.
Filters are applied as attributes over controllers or actions.
We can create custom filters by implementing IAuthorizationFilter, IActionFilter, IResultFilter or IExceptionFilter.

Creating a custom action filter

	// a custom action filter
	public class AuditFilter : FilterAttribute, IActionFilter {
		// this method is called after the action is executed
		public void OnActionExecuted(ActionExecutedContext filterContext) {
			Debug.WriteLine("OnActionExecuted is called");
		}

		// this method is called before the action is executed
		public void OnActionExecuting(ActionExecutingContext filterContext)	{
			Debug.WriteLine("OnActionExecuting is called");
		}
	}
	
	[AuditFilter]
	public ActionResult EditProfile() { 
		//..
	}
		

MVC Extensions

Route Constraints
Route Handlers
Controller Factories
Action Invokers
View Engines
Filters

Web forms vs. MVC

Web forms vs. MVC

Web forms - Advantages

Good for Rapid Application Development
Provides a rich set of UI controls
Makes to feel web as stateless through viewstate and event-driven programming model
Easy to learn

Web forms - Disadvantages

Unit testing is a pain
Viewstate increases the page size and bandwidth
Can't easy to integrate with JavaScript frameworks
Create maintainability issues for big applications
Hides the way how web works through heavy abstractions and this makes young developers not much aware of HTTP and other basic things.

MVC - Advantages

Follows Separation of Concerns by dividing an application into models, views and controllers
Loosely couples the components through interfaces making unit testing so easy
Gives full control of the generated HTML and there by makes CSS styling and JavaScript frameworks integration easy
Guides a better organization of code reducing maintenenace cost
Follows web standards making the application to reach wide range of devices
Provides good support for SEO

MVC - Disadvantages

Learning curve is steeper compared to Web Forms.
Adds complexity for simple applications
Need a strong understanding in HTTP, JavaScript and other basic stuff
No built-in UI controls

Questions?

Questions?

Post a comment!