Castle Demo App #3: Saving time and effort with advanced Monorail features

In the third part of the Castle tutorial, we look into the features of Monorail that allow us to save a lot of time and effort when developing web applications. We explore advanced Monorail concepts that help us delegate error processing and authentication to the framework and reuse templates. We also look into how Monorail integrates nicely with ActiveRecord to automatically load and modify database objects based on HTML forms.

For those of you that have just joined this tutorial, this is the third iteration of the EvilLink web application. In the first iteration, we used basic features of ActiveRecord to set up a domain model and back it with a database. In the second iteration, we created a basic web site using Monorail that allowed users to register and log in. If you have not worked with Monorail or ActiveRecord before, read those two articles before continuing with this one.

A quick note before we begin. Hammett from the Castle project was kind enough to correct me about ActiveRecord and mixing domain logic with storage. It turns out that there is a nice way to implement the repository pattern with ActiveRecord directly. Read about the ActiveRecord Mediator that allows that in this post (including the comments).

Unlike the previous two tutorials, this one will not list all the source code for all project classes and web files. We’ll just focus on the most important stuff. You can download the full source code for this iteration from here.

Let’s continue with the remaining user stories:

  • As a user, I want to record my web links online, so that I can access them from anywhere.
  • As a user, I want to review the links that I previously recorded so that I can visit the interesting sites.
  • As a user, I want to edit details and descriptions of the links that I previously recorded, so that I can keep them up to date.

To implement these stories, we will create a new controller to manage links. We will prevent anonymous users from accessing this controller by checking whether the user is logged in, and if not, redirecting them to the login page.

Modifying the model

To implement these stories, we will need to create the Link record type and describe the relationship between users and links. We add a Links collection to User class to record links that the user has registered. It’s best to have the type as a IList interface rather than a particular list to avoid data mapping problems. Instead of [Property], we mark this as [HasMany] to signal that it is a one-to-many mapping.

private IList<Link> links = new List<Link>(); 
[HasMany] 
public IList<Link> Links 
{ 
    get { return links; } 
    set { links=value; } 
}

The Link class is fairly straight-forward. The only interesting part is the other end of the one-to-many relationship. We mark it as [BelongsTo] and also specify that the Link collection should get saved and updated automatically when the User is saved.

[BelongsTo(Cascade = CascadeEnum.SaveUpdate)]
public User Owner
{
    get { return owner; } 
    set { owner= value; }
}

Dynamic binding, AR style

One of the best things about the Castle project is how we can learn and use various components in isolation, but they also have added value when used together. Monorail and ActiveRecord together allow us to write web applications with very little boiler-plate code, focusing just on the business problem at hand. In the second part of this tutorial I explained how to use data binding to automatically populate domain objects from HTTP requests. When ActiveRecord comes into the play, this data binding becomes even more powerful. We can tell Monorail to automatically fetch a record object from the database by ID and have it ready for us to either pass to the view or modify. This is very convenient for actions that should display an object or present a HTML form to edit the object. This is done using the ARFetch attribute instead of DataBind and passing the request field that represents the ID of the related record object. For example, this method signature will automatically fetch a link by id from the database and make it available to us for display:

public void Edit([ARFetch("id")] Link link) 

On the way back, we typically want to merge the database object with the request values. There is a shortcut for this as well:

public void Submit([ARDataBind("link", 
AutoLoad = AutoLoadBehavior.NewInstanceIfInvalidKey)] Link link) 

ARDataBind will first find the object in the database, then populate it with changes from the HTTP request. The only thing left to do is to verify that the link is valid and save it. AutoLoadBehavior specifies what to do if the object is not found — in this case ARDataBind will create a new object, effectively enabling us to use the same method for creating and updating links.

To use these two attributes, our controller has to extend ARSmartDispatcherController, not SmartDispatcherController. The new controller base class and the data load attributes are in the Castle.MonoRail.ActiveRecordSupport.dll library, so add a reference to that DLL as well in your controllers project.

Advanced Monorail concepts

Instead of wrapping up here, let’s see what else we can delegate to Monorail and write less code. Monorail has several more tricks to save time and effort while creating web applications.

Filters

Filters, in Monorail jargon, are methods that are executed before or after controller actions. They allow us to declaratively add infrastructural functionality to the controller code, similar to Aspect Oriented Programming (Windsor provides better support for AOP in general and we’ll discuss this in one of the following articles in this series. Monorail filters are just simple additions to controller code). For example, we can use a filter to instantly prevent anonymous users from calling any action on the Link controller. A filter is specified on the whole controller class with a FilterAttribute. This one will execute the AuthenticatedUserFilter before each action:

[FilterAttribute(ExecuteEnum.BeforeAction, typeof(AuthenticatedUserFilter))] 

The filter class (in this case AuthenticatedUserFilter) has to implement the IFilter interface from Castle.Monorail.Framework. The interface has only one method: Perform. If it returns false, the HTTP request processing will stop at that point and will not proceed to the controller. So let’s check if a user is logged in, and if not then redirect the browser to the login page:

using System; 
using System.Collections.Generic; 
using System.Text; 
using Castle.MonoRail.Framework; 
  
namespace EvilLink.Controllers 
{ 
    public class AuthenticatedUserFilter: IFilter 
    { 
        private UserContext userContext=new UserContext(); 
  
  
        public bool Perform(ExecuteEnum exec, 
          IRailsEngineContext context, Controller controller) 
        { 
            if (userContext.CurrentUserId == null) 
            {               
                context.Response.Redirect("UserOps",
     "index.ashx?goBackUrl="+context.Request.Uri); 
                return false; 
            } 
            else return true; 
        } 
    } 
} 

We can now use this filter to quickly mark all controllers that require the customer to be logged in, just by putting an attribute on the class.

Partial templates

NVelocity allows us to reuse view code in different templates by just including the file, using #parse(file) command. This is what Rails calls partial templates. For example, we’ll need to display link details after a user registers that link, but we also need to display the same details when the user browses his links. Instead of copying the same content all over the templates, we can extract that into a common view file and just include it. The important thing to remember is that the path of the included file is relative to the views folder, not the current folder. This is an example of the view that prints links using a partial template:

<h1>My Links</h1>
#if ($links.Count>0)
<ul>
	#foreach( $link in $links)
	<li>
		#parse ("Link/viewLink.vm")
	</li>
	#end
</ul>
#else
You have no saved links.
#end
#parse("Link/newLink.vm")

Helpers

NVelocity language intentionally does not allow you to perform complex scripting, to avoid mixing domain and UI code. But sometimes we want to automate generating HTML code in a more complex language. Monorail allows that with Helpers. Helpers allow us to script the UI formatting in C#. We used a forms helper in the second article of this tutorial, to build a HTML form and pre-populate it with values. There are some other interesting helpers included in the Castle distribution, for example Ajax helpers that generate Scriptaculous effects or help with Prototype communication. You can also write your own helpers and add them to the controllers using the Helper attribute.

View components

View components are a way to re-use parts of the UI dynamically in various pages. This is typically used to manage common parts of the web pages like menus.

I personally don’t use view components that much, because there are different alternatives that can provide the same functionality with just controllers. For view formatting (without any business functionality), it is often better to use Helpers. To loop through a list of objects and reuse the display functionality, I use partial templates (with NVelocity, you can use #parse to include a template file). Parts that reuse business functionality can be implemented using AJAX DIVs as well. So components are really used only when you need to re-use parts of UI that include some business functionality and layout, but you want to process that on the server as part of the same request (so no AJAX).

We use a component in this case to build the top menu bar, that will display links to log in and register if the user is not yet logged in, and display options to add and review stored links and to log out when a user is logged in. The component class is just like a mini-controller with a single action. To implement the component, we need to extend ViewComponent and override the Render method. PropertyBag is available for the component as well (it is actually shared with the controller). Because there is only one method, the component needs to explicitly specify which view gets rendered.

using Castle.MonoRail.Framework; 
namespace EvilLink.Controllers 
{ 
    public class MenuBarComponent:ViewComponent 
    { 
        private UserContext context=new UserContext(); 
  
        public override void Render() 
        { 
            if (context.CurrentUserId != null) 
                PropertyBag["appuser"] = context.CurrentUser; 
            RenderView("default"); 
        } 
    } 
} 

The view file for the component is similar to the controller view files, but it needs to be in the views\components\MenuBarComponent folder in the web site. To include this component somewhere in the view code, use #component NVelocity extension (this was added for the Castle project and it is not available in the basic NVelocity release). As components are re-usable across pages, they are typically included into the generic layout files, not into individual template views. So here is the changed default layout:

<html> 
<head><title>Evil Link v 1.0</title></head> 
<link rel="stylesheet" href="$siteRoot/views/layouts/default.css" /> 
<body> 
      #component(MenuBarComponent) 
      <hr/> 
      #if($message) 
      <div class="message"> 
            $message 
      </div> 
      #end 
  
      #if($error) 
      <div class="error"> 
            $error 
      </div> 
      #end 
  
      $childContent 
  
</body> 
</html> 

Rescues

Monorail Rescues allow us to delegate most common error handling cases, when we just display an error message to the user, to the framework. A rescue is just an alternative view that will be displayed in case of an exception, and passing the responsibility for that to the framework allow us to write less code — instead of try/catch and display error blocks in every action, we just specify an attribute. Rescues can be specified for the whole class or for individual methods, and can be called for a particular exception type or for any exception. For example, to just display an error view in case of any exceptions during processing, we can add a Rescue(“error”) attribute to the controller class. The actual view should be stored in the views\rescues folder of the web site. In the view, we can use $context to reference the rails context. See IRailsEngineContext API docs for more details on that. Most important is the fact that $context.LastException.Message will give us the exception message. So here is a simple rescue velocity file:

<div class="error"> 
$context.LastException.Message 
</div> 

Implementing the Link Controller

Armed with all this knowledge, we can now easily implement the link controller. We’ll add a filter to prevent people from using any of the link controller actions if they are not logged in, and we will also not write any error handling code &mdash instead it will be delegated to a rescue. We need to implement actions to register a new link and edit an existing link. After the user submits link details, we store them to the database and display new link information. We also want to enable users to view registered links. For that, we’ll create the following actions:

  • NewLink — display a form for a new link
  • Edit — display a form to edit an existing link
  • MyLinks — view registered links
  • Submit — process a form containing link details, either to create or edit a link
  • View — view details of a particular link

Edit and View perform the same action essentially, they just load the link details from the database and pass it on to the view to display (but they use different views). We’ll use ARFetch for Edit and View, and we use ARDataBind for Submit. NewLink and Edit should use the same visual template, and MyLinks should use that same template to display links from a collection. For that, we can use the #parse trick.

using System; 
using System.Collections.Generic; 
using System.Text; 
using Castle.MonoRail.ActiveRecordSupport; 
using EvilLink.Database; 
using Castle.MonoRail.Framework; 
namespace EvilLink.Controllers 
{ 
    [FilterAttribute(ExecuteEnum.BeforeAction, typeof(AuthenticatedUserFilter))] 
    [Rescue("error"), Layout("default")] 
    public class LinkController : ARSmartDispatcherController  
    { 
        private UserContext context=new UserContext(); 
        public void NewLink() 
        { 
            // just display the form 
        } 
        public void Submit([ARDataBind("link",
         AutoLoad = AutoLoadBehavior.NewInstanceIfInvalidKey)] Link link) 
        { 
            if (!link.IsValid()) 
            { 
                PropertyBag["link"] = link; 
                Flash["error"] = link.ValidationErrorMessages; 
                RenderView("edit"); 
                return; 
            } 
            link.Owner = context.CurrentUser; 
            link.SaveAndFlush(); 
            Flash["message"] = "Link saved"; 
            //redirect after post 
            Redirect("view.ashx?id="+link.Id); 
        } 
        // shortcut for loading the object, don't update it with request values 
        public void View([ARFetch("id")] Link link) 
        { 
            PropertyBag["link"] = link; 
        } 
        public void Edit([ARFetch("id")] Link link) 
        { 
            View(link);  
        } 
        public void MyLinks() 
        { 
            PropertyBag["links"] = context.CurrentUser.Links; 
        } 
    } 
} 

Key stuff to remember

  • Mark one-to-many relationships with [HasMany] and [BelongsTo]
  • Reuse parts of templates with #parse
  • Use helpers to perform more complex UI scripting with C#, but avoid putting any business functionality into helper classes
  • Share business functionality and UI between pages using view components
  • Delegate error handling to rescues
  • Use Filters for simple aspect-style programming with Controllers to perform authentication, logging and similar actions
  • Use ActiveRecord data binding attributes and ARSmartDispatcherController to automatically load objects from the database and merge changes from HTML forms

Next exercise

In the next part of this tutorial, we look into unit testing Monorail controllers. That tutorial should be online early next week. You can download the full source code for this iteration from here.

Meanwhile, you might be interested in coming to the “Developing Ajax Web applications with Castle Monorail” presentation that I will be doing on the 12th of June in London. It’s free, but you have to register up-front. See Skills Matter site for more information.

I'm Gojko Adzic, author of Impact Mapping and Specification by Example. To learn about discounts on my books, conferences and workshops, sign up for Impact or follow me on Twitter. Join me at these conferences and workshops:

Product Owner Survival Camp

Specification by Example Workshop

Conference talks and workshops

One thought on “Castle Demo App #3: Saving time and effort with advanced Monorail features

  1. Great article Gojko,

    Quick point, where you mention the [BelongsTo] attribute, the code beneath seems to be an exact copy of the previous code above. Is that right? Should it not show an example from the User class?

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>