Tuesday 24 February 2009

ASP.net MVC Framwork Part 2

In my previous post, I wrote about Microsoft ASP.Net MVC framework and how it resolves the complexity of implementing model-view-controller design pattern in ASP.net web applications. In this post, I will compare what it takes to use MVC pattern in an ASP.net web application and do the same using the ASP.Net MVC framework.

The QuickShop Application
For my example, I will create a very very simple online store, which sells such a small number of items that they can be listed in a drop down list. We will also assume that the name of products are sufficient enough for the client and that all payment is done offline. Purchase through the online store has three steps in total. The first page shows the list of products and allow customers to select product and quanity. The second page shows a confirmation message with the selected product and quanity and the last page creates the order and takes the user back to first page.

Database
The databae of our simple application is also very simple. The database has two tables, Product & Order. The product table contains all the products present in the store and the Order table contain all the Orders, as shown


ASP Web Application
To implement the controller of our application, we create an abstract class called "Process". The class would contain a list of "Actions". The controller would take input from view (ASP.Net pages) and move from one action to another, while working with Model, which is constituted of the database and entity classes.
namespace QuickShopWeb
{

using System.Collections.Generic;

public delegate void ActionChangedEventHandler(object sender, System.EventArgs e);


[System.Serializable]
public abstract class Process
{
private List _actions;
private int _currentActionIndex;

public event ActionChangedEventHandler OnActionChanged;

public List Actions
{
get{ return _actions; }
}

public Action CurrentAction
{
get{ return _actions[_currentActionIndex]; }
}


internal void SetActions(List actionsToSet)
{
this._actions = actionsToSet;

foreach (Action action in this._actions)
{
action.OnCompletion += new ActionCompletionEventHandler(this.Action_OnCompletion);
}
}

private void Action_OnCompletion(object sender, System.EventArgs e)
{
if (this._currentActionIndex >= this._actions.Count - 1){
// Restart
this._currentActionIndex = 0;
}
else{
// Move to next action
this._currentActionIndex++;
}
// Notify the View that we've moved on to a new action
if (this.OnActionChanged != null) {
this.OnActionChanged(this, e);
}

}
}
}


It contains a list of objects of type "Action". There is an indexer and a method that set the list of Actions. Also defined is an event and and event handler. The event is invoked when an action is completed and the EventHandler simply moves the indexer to the next Action in the list.

We add the [System.Serializable] attribute because we would need to persist Controller between views and this is achieved by keeping the controller object in HTTP session object.

We next look at the Action class, which is again a Serializeable abstract class, defines an event for ActionCompletion and a method called Complete. The class is defined as follows:

namespace QuickShopWeb
{
using System;
internal delegate void ActionCompletionEventHandler(object sender, EventArgs e);

[System.Serializable]
public abstract class Action
{
internal event ActionCompletionEventHandler OnCompletion;

internal void Complete(EventArgs e)
{
if (this.OnCompletion != null)
{
this.OnCompletion(this, e);
}
}
}
}
Now that the groundwork is done, all we need now is to define the specific process for our application. Our simple application has three actions
  1. IndexAction: Need to retrieves all the products display them in the view
  2. Confirm: Need to shows confirmation message in the view
  3. CreateOrder: Need to create new order record.
Our process class looks like following:

namespace QuickShopWeb
{
using System.Web;
using System.Collections.Generic;

[System.Serializable]
public class ShopProcess : Process
{
public int ProductId { get; set; }
public int Quantity { get; set; }
public string ProductName { get; set; }

public ShopProcess()
{
List actions = new List();
actions.Add(new IndexAction());
actions.Add(new Confirm());
actions.Add(new CreateOrder());

this.OnActionChanged += new ActionChangedEventHandler(ProcessActionChanged);
this.SetActions(actions);
}

private void ProcessActionChanged(object sender, System.EventArgs e)
{
RedirectToAction(CurrentAction);
}

public void RedirectToAction(Action action)
{
switch(action.GetType().Name)
{
case "IndexAction":
HttpContext.Current.Response.Redirect("~/View/Index.aspx");
break;

case "Confirm":
HttpContext.Current.Response.Redirect("~/View/Confirm.aspx");
break;

case "CreateOrder":
HttpContext.Current.Response.Redirect("~/View/Complete.aspx");
break;
}
}
}
}
As you can see, the ShopProcess initiates all action and creates an EventHandler for OnCompletion event of all actions. The event handler simply redirects to appropriate view.

Now that we have the controller part working, next is to create view. I will explain the only the Index.aspx page. Views for other actions are similar and can be easily understood by going through the code. The default aspx page created an object of type ShopProcess and added it to the Session variable as shown:


public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
ShopProcess goShopping = new ShopProcess();
Session["CurrentProcess"] = goShopping;
goShopping.RedirectToAction(goShopping.CurrentAction);
}
}
This starts the process and takes the user to the index.aspx page. The index.aspx codebehind file looks like:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace QuickShopWeb.View
{
public partial class Index : System.Web.UI.Page
{
public ShopProcess CurrentProcess
{
get
{
return (Session["CurrentProcess"] as ShopProcess);

}
}
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
IndexAction action = CurrentProcess.CurrentAction as IndexAction;
foreach (Product product in action.Products)
{
ProductDropDownList.Items.Add(new ListItem(product.ProductName, product.ProductId.ToString()));
}
}
}

protected void OrderButton_Click(object sender, EventArgs e)
{
CurrentProcess.ProductId = int.Parse(ProductDropDownList.SelectedValue);
CurrentProcess.Quantity = int.Parse(QuantityTextBox.Text);
CurrentProcess.ProductName = ProductDropDownList.SelectedItem.Text;

CurrentProcess.CurrentAction.Complete(e);
}
}
}
The index.aspx page (view) extracts data passed to it from the contoller and displays it to the user. When user input some data, the view passes it to the controller and set the current action to complete (as shown in the OrderButton_Click) event.

The complete listing of web application can be downloaded from this link.

Using MVC Framework
Now, we will create the same application using MVC framework. I have created this example using the Microsoft MVC Release Candidate 1. If you have not downloaded it already, you can download it free from here.

We create a new solution and this time instead of choosing "ASP.Net Web Application", we choose "ASP.Net MVC Web Application" as shown:

The next step in the wizard would ask you if you want to create a unit test project. I select the option "No, do not create a unit test project" for my application. When you click OK, you will see that the wizard has created classes for Controller, home page, about page, etc. We will ignore them now.

What I will do now is to add a dbml class that points to our QuickShop database. Then, click on the HomeController.cs class and rewrite the code for Index() method, so that it returns a list of all Products, so the code would look like:

public ActionResult Index()
{
var products = from p in db.Products orderby p.ProductName select p;
return View(products.ToList());
}
By default the Index method is invoked for the Index page and this list of products would be available to the Index.aspx page (View). All we need to do is to create a codebehind file for Index.aspx and inherit it from System.Web.Mvc.ViewPage<List<Product>> So the codebehind class for our Index page would look like

namespace QuickShop
{
using System;
using System.Collections.Generic;
using System.Web;

public partial class Index : System.Web.Mvc.ViewPage>
{
}
}

To access the data returned from the controller, the aspx page (view) needs to use the ViewData.Model property. The complete listing of our Index.asp page is shown below

<%@ Page Language="C#" AutoEventWireup="false" CodeBehind="Index.cs" Inherits="System.Web.Mvc.ViewPage" %>
<%@ Import Namespace="QuickShop" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Quick Shop</title>
</head>
<body>
<h1>Quick Electronic Shop</h1>
<br />
<br />
<div>
<form method="post" action="/Home/Confirm">
Select Product
<br />
<select name="product" style="width:200px;">
<%
foreach(Product product in (ViewData.Model as List<Product>))
{
Response.Write( string.Format("<option value=\"{0}\">{1}</option>", product.ProductId , product.ProductName ));
}
%>
</select>
<br />
<br/>
Quantity
<br />
<input type="text" name="quantity" style="width:200px;"/>
<br />
<br />
<input type="submit" value="Order" />
</form>

</div>
</body>
</html>
Please note that we are not using any server side components in this page and the action of the forms is set to "/Home/ConfirmOrder". This would automatically invoke the ConfirmOrder method in the Home controller. Moreover, the form input variables are automatically passed as parameters to the method. So, the signature of our Confirm method would look like:

public ActionResult Confirm(string product, string quantity ) { }
Compare this will all the code we had to write in our ASP Web application.

In the confirm method, all we need to do is to return an object in the actionResult, which contains
details of the product and quantity set in the previous page. The complete code of the confirm method is

public ActionResult Confirm(string product, string quantity )
{
string productName = string.Empty;
var products = from p in db.Products where p.ProductId == int.Parse(product) select p;
if (products != null)
{
foreach (Product p in products)
{
productName = p.ProductName;
break;
}
}
Dictionary dict = new Dictionary();
dict.Add("product",product);
dict.Add("productName", productName);
dict.Add("quantity", quantity);
return View( dict );
}
As you can see, the method returns the actionResult with a Dictionary object, containing all the information needed by view. The confirm.aspx page (view) would display this method and show a confirm button, which will set the action to "CreateOrder". The listing of confirm.aspx page is shown below:
<%@ Page Language="C#" AutoEventWireup="false" Inherits="System.Web.Mvc.ViewPage" Codebehind="~/Views/Home/Confirm.cs" %>
<%@ Import Namespace="QuickShop" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Quick Shop</title>
</head>
<body>
<h1> Confirm your order...</h1>
<div>
<%
Dictionary<string, string> values = (ViewData.Model as Dictionary<string, string>);
%>
You have chose to buy <b><%=values["quantity"]%></b> pieces of <B><%=values["productName"]%></B>. Are you sure?
<form method="post" action="/Home/CreateOrder">
<input type="hidden" name="product" value="<%=values["product"]%>"/>
<input type="hidden" name="quantity" value="<%=values["quantity"]%>"/>

<input type="submit" value="confirm />
</form>
</div>
</body>
</html>

Now, the last bit of detail needed in our MVC application is to create a method for CreateOrder in the HomeController. This method again takes two parameters -same as the input submitted through the HTML form. The method would create a new order record in the database and then redirects the view back to Index page.
public ActionResult CreateOrder(string product, string quantity)
{
Order newOrder = new Order();

newOrder.OrderDate = DateTime.Now;
newOrder.ProductId = int.Parse(product);
newOrder.Quantity = int.Parse(quantity);
db.Orders.InsertOnSubmit(newOrder);
db.SubmitChanges();

return RedirectToAction("Index");
}
The complete listing of the quickshop application using MVC can be downloaded from this link.

Conclusion
I hope that the example, although overly simplistic, would have helped you in understanding how MVC framework simplifies using the MVC design pattern in the asp.net web applications. The framework does a lot of plumbing work for in getting and setting data from HTTP posts. For its functionalty the MVC framework uses it's own HTTPHandler.

In my next post, I will write about what happens behind the scenes in MVC framework and how does it work internally.

Sunday 15 February 2009

ASP.net MVC Framwork

I remember from early days of my career, when I was working on Microsoft ASP 3.0 technology, keeping a separation of business and presentation logic was quite a challenge. Although, the critical business logic was often coded in COM components, which were called from ASP Page, but the ASP Page would still contain certain logic on which component to call and how the process flow in the application would happen. The resulting ASP files were often a horrid mesh of server side VB Script portions, client side javascript portions and HTML/DHTML to render a page.

To put some method to madness, and to achieve some separation of presentation and business logic, I was taught to create each ASP page with a “Main” method in it, called in the first command of the page. The Main method would provide a single point of entry to the page and used to look like

<% Call Main

Sub Main
Select _pageMode:
Case ADD_MODE:
'code to show the form in add mode

Case INSERT_MODE:
'code to add records

Case EDIT_MODE:
'code to add record Case EDIT_MODE

Case UPDATE_MODE:
'code to update records

.....
.....
End Select
End Sub
%>


....
....



So, what we had was essentially identification of action at the start of page and then business logic to do specific work for that action. The presentation of page would follow after all the server side script was executed. If there were any server side scriptlets in the HTML section, they were used just to present data.

As then, the separation of presentation and essential business logic is still identified as one of the salient features of application maintainability. And the Model View Controller pattern has fast become one of the most popular ways of achieving this.

The advent of ASP.Net saw the whole programming model of working with ASP pages to a more event driven structure. Certain events are fired are certain stage of a page’s execution. To do something similar in ASP.Net, an ordinary developer would identify the event where the code to handle the specific action needs to be written and then write down the code in the handler of that event. This model, along with the code behind ability of ASP.Net provides separation of presentation logic from business logic, but the code is still driven by view.

The purists would argue that in a real MVC pattern, the Controller controls the process flow and maps “actions” to appropriate “processes”. In other words, it would gather the action done by the user on the view, determine the state of application and then invoke the appropriate model.

The new Microsoft MVC framework, recently released by Microsoft is a lovely initiative to allow you to use the MVC framework without doing zillions of line of code. It also provides an alternative “off the shelf” approach to designing web applications for people who do not wish to use the server components, Post Backs, View state, etc.

In my next post, I will write about using MVC pattern in a simple ASP.Net web application and demonstrate how simple it is to do so with the ASP.Net MVC framework. Also, you will be surprised to note, how similar our controller would be the above mentioned template that was suggested for ASP.

Wednesday 11 February 2009

Reading X509 Certificates from remote machines

Today, I got to write some code to read X509 certificates remotely from machines on local network. The requirement was to read certificates installed in certificate stores on remote machines and verify whether or not they have expired.

It may sound trivial but I found that it was not possible to do it using classes in the System.Security.Cryptography.X509Certificates namespace. For some reason, Microsoft have not included support to read remote certificate stores from the X509Store class, which otherwise makes working with X509 really easy.


Reading Certificates from local machine
If you want to read certificates locally on your machine, the X509Store class is very useful and you can read and manipulate certificates with minimal code, as shown below:

X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
try
{
store.Open(OpenFlags.ReadOnly);
}
catch (Exception ex)
{
throw new Exception("Error opening certificate store", ex);
}
foreach (X509Certificate cert in store.Certificates)
{
/// do whatever you want to read with certificate here
}


The X509Store can open with OpenFlags.Readonly and OpenFlags.ReadWrite option. The StoreLocation can be StoreLocation.LocalMachine or StoreLocation.CurrentUser and the StoreName can be any of the 8 different options.
(StoreName.My is equivalent to Personal certificate store that you will see when you open Certificates from MMC Console)



Reading Certificates from remote machine

One way to do it is to use directory services and find out the certificates of remote machine using DirectorySearcher and DirectoryEntry class in the System.DirectoryServices namespaces. This is described in the blogpost Get X509Certificate2 from a LDAP Server or Remote Machine. I found it a bit of overkill.

Another way to do it is to use the old Microsoft CAPICOM COM APIs. This requires that the CAPICOM ActiveX controls be installed along with the application and the CAPICOM APIs be p/invoked from your managed code. The most obvious downside of this is that the whole CAPICOM SDK would needs to be installed and distributed with your application.

The best option that I found was to use the ever reliable CertOpenStore windows API. The API is very powerful and if you have some experience with Windows programming and using P/Invoke to call windows API, the code would be most simple and straightforward for you to work with. Of course, the best practice is to encapsulate it in a class and make the P/Invoke hidden from the rest of the application

The following class would do it for you. For illustration purposes, I have used the classes from the System.Security.Cryptography.X509Certificates namespace. You can do the same using only the APIs and not given computer name at all in the last parameter.


using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Runtime.InteropServices;

public enum CertStoreName
{
MY,
ROOT,
TRUST,
CA
}
public class CertStoreReader
{

#region P/Invoke Interop
private static int CERT_STORE_PROV_SYSTEM = 10;
private static int CERT_SYSTEM_STORE_CURRENT_USER = (1 << 16);
private static int CERT_SYSTEM_STORE_LOCAL_MACHINE = (2 << 16);

[DllImport("CRYPT32", EntryPoint = "CertOpenStore", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern IntPtr CertOpenStore(int storeProvider, int encodingType, int hcryptProv, int flags, string pvPara);

[DllImport("CRYPT32", EntryPoint = "CertEnumCertificatesInStore", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern IntPtr CertEnumCertificatesInStore(IntPtr storeProvider, IntPtr prevCertContext);

[DllImport("CRYPT32", EntryPoint = "CertCloseStore", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern bool CertCloseStore(IntPtr storeProvider, int flags);

#endregion


public string ComputerName { get; set; }


private readonly bool isLocalMachine;
public CertStoreReader(string machineName)
{
ComputerName = machineName;
if (machineName == string.Empty)
{
isLocalMachine = true;
}
else
{
isLocalMachine = string.Compare(ComputerName, Environment.MachineName, true) == 0 ? true : false;
}
}

public X509Certificate2Collection GetCertificates(CertStoreName storeName)
{
X509Certificate2Collection collectionToReturn = null;
string givenStoreName = GetStoreName(storeName);

if (givenStoreName == string.Empty)
{
throw new Exception("Invalid Store Name");
}

if (isLocalMachine)
{
X509Store store = new X509Store(givenStoreName, StoreLocation.LocalMachine);
try
{
store.Open(OpenFlags.ReadOnly);
}
catch (Exception ex)
{
throw new Exception("Error opening certificate store", ex);
}
collectionToReturn = store.Certificates;
}
else
{
try
{
IntPtr storeHandle = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0, CERT_SYSTEM_STORE_LOCAL_MACHINE, string.Format(@"\\{0}\{1}", ComputerName, givenStoreName));
if (storeHandle == IntPtr.Zero)
{
throw new Exception(string.Format("Cannot connect to remote machine: {0}", ComputerName));
}

IntPtr currentCertContext = IntPtr.Zero;
collectionToReturn = new X509Certificate2Collection();
do
{
currentCertContext = CertEnumCertificatesInStore(storeHandle, currentCertContext);
if (currentCertContext != IntPtr.Zero)
{
collectionToReturn.Add(new X509Certificate2(currentCertContext));
}
}
while (currentCertContext != (IntPtr)0);

CertCloseStore(storeHandle, 0);
}
catch (Exception ex)
{
throw new Exception("Error opening Certificate Store", ex);
}
}

return collectionToReturn;
}

private static string GetStoreName(CertStoreName certStoreName)
{
string storeName = string.Empty;
switch (certStoreName)
{
case CertStoreName.MY:
storeName = "My";
break;

case CertStoreName.ROOT:
storeName = "Root";
break;

case CertStoreName.CA:
storeName = "CA";
break;

case CertStoreName.TRUST:
storeName = "Trust";
break;
}
return storeName;
}
}