Monorail and ASP.NET MVC
Now, if you are sold on the principle of clean separation of your model, view and controller, and you want to start using application controllers and separated views then you could roll your own implementation. A better solution however is to use an off-the-shelf alternative to WebForms such as Monorail or, in the future perhaps, the ASP.NET MVC framework to provide this type of framework.
Monorail
The Castle Project was founded by Hamilton Verissimo de Oliveira originally to develop an Inversion of Control container but later expanded its mission to common enterprise and web applications. Key projects include: MicroKernel & Windsor IoC containers, the MonoRail web framework, Active Record for NHibernate, Aspect # AOP framework, and a Dynamic Proxy generator.
Monorail is an MVC web framework built on the ASP.NET platform.
Monorail has distinct controllers and views. This makes the controllers easy to test. A Monorail controller for example looks something like this:
[Layout("default"), Rescue("generalerror")]
public class ProductController : SmartDispatcherController
{
public void List()
{
PropertyBag["products"] = Product.FindAll();
RenderView("list");
}
}
Here ProductController is our controller, identified by its base class (ultimately Controller). The controller exposes a number of public methods, which Monorail terms actions. Actions are requests to the controller – to provide a response to a request. Within the action we ask the model (Product) for data, which we pass to the view (via PropertyBag) for display. We then pick an appropriate view and tell it to render (Monorail will actually render the view with the same name as the action by default – we just show it here for clarity).
MonoRail, acting as the front controller, decides which (application) controller to display using the url of the request. The url which has the form <site>\<area>\<controller>\<action>.rails
The view is a template written in NVelocity (though you can use other view engines like Brail), that takes the data from the model (via the property bag) and generates html for the response:
<h3>Product list</h3>
<p>
<a href="new.rails">Create new Product</a>
</p>
<table width="100%" border="1" cellpadding="2" cellspacing="0">
<tr>
<th>Id</th>
<th>Name</th>
<th>Supplier</th>
<th> </th>
</tr>
#foreach($product in $products)
<tr>
<td align="center">$product.Id</td>
<td align="center">$product.Name</td>
<td align="center">$product.Supplier.Name</td>
<td align="center">
<a href="edit.rails?id=${product.Id}">Edit</a> |
<a href="delete.rails?id=${product.Id}">Delete</a>
</td>
</tr>
#end
</table>
Monorail uses a composite view pattern equivalent to master pages. Note that on the controller class we attribute the Layout. The layout is the master for the controller and the view we render in response to the request is the child of this master.
In this case our layout looks like:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>Layout</title>
<link rel="stylesheet" href="$siteRoot/Content/css/base.css" />
</head>
<body>
$childContent
</body>
</html>
Where $childContent is the placeholder for our view.
The model is just a Plain Old C# object, likely representing an object within our domain. In this case we have a simple Product object. We use the Castle Project’s Active Record framework build on NHibernate to provide persistence for this object:
[ActiveRecord]
public class Product : ActiveRecordBase
{
[PrimaryKey]
public int Id {get;set;}
[Property]
public string Name {get;set;}
[Property]
public decimal Price {get;set;}
[BelongsTo("SupplierId")]
public Supplier Supplier {get;set;}
public static Product[] FindAll()
{
return (Product[]) FindAll(typeof(Product));
}
public static Product FindById(int id)
{
return (Product) FindByPrimaryKey(typeof(Product), id);
}
}
Hopefully you can see the clean separation of concerns that MonoRail enables.
You can work through the example this code was taken from at: http://www.castleproject.org/monorail/gettingstarted/index.html
More...