Thursday, September 10, 2009

The 3 Musketeers: Model, View and Controller using HTTPHandler – Part 1

Introduction


Please feel free to download my free 500 question and answer videos which covers Design Pattern, UML, Function Points, Enterprise ApplicationBlocks, OOP'S, SDLC, .NET, ASP.NET, SQL Server, WCF, WPF, WWF, SharePoint, LINQ,SilverLight, .NET Best Practices @ http://www.questpond.com/


Introduction and Goal

In this section, we will learn about the basics of MVC and then see how we can implement the same in ASP.NET using HttpHandlers.

Warning

Microsoft has released the ASP.NET MVC Framework and the second tutorial will talk about that. In this tutorial, we will try to understand how we can implement MVC on pure ASP.NET. This will make our fundamentals more clear when we see the ready made framework of MVC ASP.NET.

Pre-requisite

We would suggest you to read the concept of HttpHandlers and HttpModules from the following article named "The Two Interceptors: HttpModule and HttpHandler".



The World is About Action, Format and Data

When we talk about any project, it's all about action. Depending on action, the user sees some data in some kind of format. Let’s take up a small three liner customer project requirement shown below:
  • User goes to the home page.
  • User can see customer data with sales figure.
  • User can see customer data without sales figure

    From the requirement, you can typically classify three entities: one is the action, second the view depending on the action and third the data to be displayed for the particular action and format.

The above figure shows how the action, view and model / data will work together to fulfill our requirements. We have three actions from the above requirement:
  1. The user can go to the home page
  2. S/he can view the customer with sales
  3. S/he can view the customer without sales
Each of these actions is mapped to view / Web page which need to be displayed. For instance, when the user does the action GotoHome, he will be shown Home.aspx page. Every view will use the model to get data. Currently for the Home.aspx, there is no model but the customer views will connect with the model to display the data.
The final table we conclude is as below:

The Problem of Tight Coupling and Solution

If we closely visualize the above problem, we can figure the two big tight couplings: one is the action with the view and the view with the model, i.e. data. In practical scenarios, we can always think about many views which can tie up to the same models and many actions resulting the same view. So if decouple them we can avoid redundant coding and a better reusable framework.


So what we do is we give this work of co-ordination to a third party i.e. the controller. Now all the actions are sent to the controller. The work of the controller is to update and load the model and then tie that model with the view depending on the action.

Implementing MVC in ASP.NET

We will take the same example of the three liner customer project which we discussed previously. Below is a visual view of things and how it will move. If the action is GotoHome, Home.aspx page will be shown with two links: one is to view customer with sales and the other is to view customer without sales. If the action is ViewCustomersWithOutSales, it will display a simple view where the customer details are shown without sales figure. If the action is ViewCustomerWithSales, it will show a display of customer with its sales figure.


The Easy Musketeer Model

Let’s first understand the model part of the MVC. This is the simplest part to start with and then we will proceed towards more complicated things like controller and views. Model is nothing but a class which will provide necessary data source to the views.
The below code shows a customer data. It has three properties:
  1. Customer name
  2. Address
  3. The sales amount for the customer
public class clsCustomer
{
 private string _strCustomerName;
 private string _strAddress;
 private double _dblSales;
 public string CustomerName
 {
  set
  {
   _strCustomerName = value;
  }
  get
  {
   return _strCustomerName;
  }
 }
 public string Address
 {
  set
  {
   _strAddress = value;
  }
  get
  {
   return _strAddress;
  }
 }
 public double Sales
 {
  set
  {
   _dblSales = value;
  }
  get
  {
   return _dblSales;
  }
 }
}
Correspondingly, I have made a collection where I will be loading some dummy records. In real projects, this class will connect to the database to load data. To keep the article simple, I have hardcoded data in the customer collection.
public class clsCustomers : CollectionBase
{
 public clsCustomers()
 { 
 }
 public void LoadCustomers()
 {
  Add("Shiv", "Mulund", 20);
  Add("Raju", "Mumbai", 20);
  Add("Manish", "Delhi", 20);
  Add("Lalu", "Nepal", 20);
  Add("Khadak", "Ratoli", 20);
  Add("Shaam", "Ghatkopar", 20);
 }
 void Add(string strCustomerName, string strAddress, double dblSales)
 {
  clsCustomer objCustomer = new clsCustomer();
  objCustomer.Address = strAddress;
  objCustomer.CustomerName = strCustomerName;
  objCustomer.Sales = dblSales;
  List.Add(objCustomer);
 }
}

The Second Musketeer: The View

We have three files in our view:
  1. Home.aspx
  2. DisplayCustomerWithOutSales.aspx
  3. DisplayCustomerWithSales.aspx
Home.aspx is pretty simple and only has the links.
The DisplayCustomerWithOutSales.aspx will bind the customer’s data given by the controller. Controller will pass the data using the ASP.NET context.
public partial class DisplayCustomerWithOutSales : System.Web.UI.Page
{
 clsCustomers objCust;
 protected void Page_Load(object sender, EventArgs e)
 {
  objCust = (clsCustomers) Context.Items["Customers"];
  dtgWithOutSales.DataSource = objCust;
  dtgWithOutSales.DataBind();
 }
} 
The DisplayCustomerWithSales.aspx also has the same code. You can see the same in the source code attached with this tutorial.

The Third Tough Musketeer: Controller

We would suggest you to read the concept of HttpHandlers and HttpModules.
For every action, we have a controller class. In real projects, you can always map multiple actions to one controller class. To make the tutorial simple, I have kept one controller for every action.
The controller will do three things:
  1. Load the model.
  2. Pass the model to the view.
  3. Load the view and send it to the end user.

    Below is the home handler class. As it’s not tied up with any data, it does not call any model and just invokes the view.
public class clsHomeHandler : IHttpHandler
{
 public void ProcessRequest(System.Web.HttpContext context)
 {
  context.Server.Transfer("./view/Home.aspx");
 }
 public bool IsReusable
 {
  get
  {
   return true;
  }
 }
}
Customer without sales controller class: This loads the model and adds the model data in the context. If you remember, in the view code snippet the data is taken from the context. After that, it just loads the view i.e. DisplayCustomerWithSales.aspx.
public class clsHandlerCustomerWithSales : IHttpHandler
{
 public void ProcessRequest(System.Web.HttpContext context)
 {
  clsCustomers objCustomers = new clsCustomers();
  objCustomers.LoadCustomers();
  context.Items.Add("Customers", objCustomers);
  context.Server.Transfer("./view/DisplayCustomerWithSales.aspx");
 }
 public bool IsReusable
 {
  get
  {
   return true;
  }
 }
}
The third controller is customer without sales. The code is self explanatory as it maps with the previous code snippet logic.
public class clsHandlerCustomerWithOutSales  : IHttpHandler
{
 public void ProcessRequest(System.Web.HttpContext context)
 {
  clsCustomers objCustomers = new clsCustomers();
  objCustomers.LoadCustomers();
  context.Items.Add("Customers", objCustomers);
  context.Server.Transfer("./view/DisplayCustomerWithOutSales.aspx");
 }
 public bool IsReusable
 {
  get
  {
   return true;
  }
 }
}

The Web.Config File and the HttpHandler Section

In Web.config file, we just map the action with the handlers. The actions are nothing put paths currently.
<httpHandlers>

<add verb="*" path="GoToHome" type="Controller.clsHomeHandler, Controller"/>

<add verb="*" path="ViewCustomersWithOutSales"
 type="Controller.clsHandlerCustomerWithOutSales, Controller"/>

<add verb="*" path="ViewCustomersWithSales"
 type="Controller.clsHandlerCustomerWithSales, Controller"/>

</httpHandlers>
So GoToHome invokes the home page as shown in the below figure:


ViewCustomersWithSales action invokes the data with sales:


Action ViewCustomerWithOutSales invokes the customer data without sales figures:


Source Code



Download the Source code from here

1 comment:

Anonymous said...

And so too happens:)