ASP.NET MVC Tip #35 – Use the NHaml View Engine

In this tip, I explain how you can use the NHaml view engine as the view engine for an ASP.NET MVC application. I demonstrate how to create NHaml views that display both static content and database records. I also discuss how you can use master pages and user controls with the NHaml view engine.

In this tip, I explain how you can use the NHaml view engine when building an ASP.NET MVC application. The NHaml view engine is an alternative view engine to the default Web Forms view engine. NHaml is a port of the popular RAILS Haml view engine for the .NET framework.

Why use NHaml? NHaml enables you to overcome the verbosity of XHTML. What JSON is to XML, NHaml is to XHTML.

XHTML is an extremely verbose language. You need to do a lot of typing to do anything. For example, if you want to display some text in bold and italics, you have to type the following:

<strong><em>You should never yell!</em></strong>

The NHaml syntax for building a view is extremely terse. If you want to display some text in bold and italics, you can just type the following:

%strong
  %em You should never yell!

Notice that you don’t need to create a closing <strong> or <em> tag. The NHaml template processor creates these tags for you automatically.

Spaces are extremely important when using NHaml. You use spaces to indicate which element is contained in another element. The <em> tag gets rendered in the <strong> tag because the <em> tag is indented by two spaces beneath the <strong> tag.

Another advantage of this terse syntax is that it makes it easier to mix script with your XHTML markup. Using the Web Forms view engine, here’s how you would display a set of database records stored in view data:

    <ul>
    <% foreach (var m in ViewData.Model)
       { %>
        <li>
        <%= m.Title %>
        </li>
    <% } %>
    </ul>

Here’s how you would format the same set of database records with the NHaml view engine:

  %ul
    - foreach (var m in ViewData.Model)
      %li =m.Title

Depending on the configuration of your brain (your innate sensitivity to spaces), you will either find the NHaml view engine appealing or not. You will either find an NHaml view unreadable or you will be enamored by its terse simplicity. If you are a member of the latter camp, read on.

Installing and Configuring NHaml

The primary developer behind NHaml is Andrew Peters. You can read his blog entries on NHaml at:

http://andrewpeters.net/category/nhaml/

He is releasing NHaml under the MIT open source license (one of the most permissive of the open source licenses). Anyone can download the source code and use NHaml in both commercial and non-commercial applications.

In order to use NHaml, you must complete the following steps:

Step 1 – Download the Source Code

You can download the entire source code for NHaml from the Google Code website at:

http://code.google.com/p/nhaml/

Google Code uses Subversion for its source control system. To download the NHaml code, you’ll need to use a Subversion client. I recommend that you download the TortoiseSVN client from:

http://tortoisesvn.net/downloads

After you install the TortoiseSVN client, you can download the source code for NHaml by creating a new folder on your computer (anywhere), right-clicking the new folder, and selecting the menu option SVN Checkout (see Figure 1). Enter the following URL for the URL of the repository:

http://nhaml.googlecode.com/svn/trunk/

After you click the OK button, all of the files from the Google Code repository for NHaml will be downloaded to your computer.

Figure 1 – Checkout of NHaml from Google Code

clip_image002

Step 2 – Add References to the NHaml Assemblies

Before you can use NHaml with a new ASP.NET MVC project, you must add the necessary assembly references to the project. After creating a new ASP.NET MVC project, select the menu option Project, Add Reference. Under the Browse tab, navigate to the folder that contains the NHaml source code (the folder you created in the previous step).

You need to add references to the following two assemblies:

NHaml.dll

NHaml.Web.Mvc.dll

Step 3 – Use the NHaml Controller Factory

The default view engine for ASP.NET MVC is the Web Forms view engine. In order to switch to the NHaml view engine, you need to enable the NHaml Controller Factory in your application’s Global.asax file. Modify your Global.asax file so that it looks like Listing 1.

Listing 1 – Global.asax.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using NHaml.Web.Mvc;

namespace Tip35
{
    public class GlobalApplication : System.Web.HttpApplication
    {
        public static void RegisterRoutes(RouteCollection routes)
        {
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

            routes.MapRoute(
                "Default",
                "{controller}/{action}/{id}",  
                new { controller = "Home", action = "Index", id = "" }            );

        }

        protected void Application_Start()
        {
            ControllerBuilder.Current.SetControllerFactory(new NHamlControllerFactory());
            RegisterRoutes(RouteTable.Routes);
        }
    }
}

Only one line of code has been added to the Global.asax.cs file in Listing 1. The NHaml controller factory is registered as the default controller factory with the following line of code:

ControllerBuilder.Current.SetControllerFactory(new NHamlControllerFactory());

Step 4 – Modify the Web Configuration File

There is one final step that you must complete before using NHaml. You must add a new NHaml section in your web configuration file.

The NHaml section is used to set whether or not NHaml is in production mode or development mode. In production mode, views are not recompiled automatically when the source of a view is changed. Therefore, while developing an application that uses NHaml, you’ll want to put your application in development mode. When you are ready to go live, you’ll want to place your application in production mode.

Add the following element within your root web configuration (web.config) file configuration\configSections element:

<section 
  name="nhaml" 
  type="NHaml.Configuration.NHamlSection, NHaml" />

Next, add the following element right below the closing tag of the configSections element:

<nhaml 
  production="false" 
  compilerVersion="3.5" />

This configuration element places your NHaml application in development mode.

Creating an NHaml View

You create an NHaml view by creating a file that ends with the extension .haml. Because Visual Studio does not have an NHaml view template, you must create NHaml views by creating some other file type (such as an HTML file) and changing the file extension to .haml.

A sample NHaml view is contained in Listing 2.

Listing 2 – \Views\Home\Index.haml

!!!
%html{xmlns="http://www.w3.org/1999/xhtml"}
  %head
    %title My Index View
  %body
    %h1
      =ViewData["message"]

The NHaml Index view in Listing 2 is a really simple view. It contains mostly static XHTML content. The only dynamic content is the view data displayed in the body of the view (see Figure 2). The value of the message key from view data is displayed.

Figure 2 – The NHaml Index View

image

The view in Listing 2 renders the XHTML document in Listing 3. This is a valid XHTML document. Comparing the sizes of the files in Listing 2 and Listing 3 illustrates the motivation behind using the NHaml view engine.

Listing 3 – Index.haml Rendered Output

<!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>
    <title>My Index View</title>
  </head>
  <body>
    <h1>
      Welcome to ASP.NET MVC!
    </h1>
  </body>
</html>

Realize that spaces are extremely important within a NHAML view. You use exactly two spaces to indicate a nesting relationship with the element in the preceding line. When building NHaml views, I recommend that you select the Visual Studio menu option Edit, Advanced, View White Space. Selecting this menu option will make it easier to see the spaces in your views (see Figure 3).

Figure 3 – Show White Space Enabled

clip_image004

Displaying Database Data

You can use view data within an NHaml view to represent database data. For example, the view in Listing 4 displays all of the records from the Movies database table by retrieving the records from view data (see Figure 4).

Figure 4 – Displaying database data with NHaml

clip_image006

Listing 4 – Movies.haml

!!!
%html{xmlns="http://www.w3.org/1999/xhtml"}
  %head
    %title My Index View
  %body
  %h1 Movie List
  %ul
    - foreach (var m in ViewData.Model)
      %li =m.Title

Notice that the foreach statement is preceded by a dash -. You use a dash to indicate that the code on the line should be evaluated as a statement instead of an expression. You use the equal sign = to indicate that the following code should be output to the browser.

There is no concept of a typed NHaml view. The NHaml engine does some internal magic to cast the Model object to the right type.

Using Master Pages and Partials

The NHaml view engine works with master pages (layouts) and user controls (partials). You can use a master page to create a common layout for the NHaml views in your application and you can use user controls to reuse visual content across multiple views.

The use of master pages in NHaml is driven by convention. You create a file named Application.haml in your Shared folder. This file becomes the master page for your application automatically.

For example, the file in Listing 5 acts as a master page.

Listing 5 – \Views\Shared\Application.haml

!!!
%html{xmlns="http://www.w3.org/1999/xhtml"}
  %head
    %title My Application
  %body
  %h1 Master Page
  _

Notice that the final line in Listing 5 consists of a single underscore _. This underscore marks the region that can be overridden in a particular view (the underscore acts like a ContentPlaceHolder control).

The NHaml view in Listing 6 uses the master page.

Listing 6 -- \Views\Home\ShowMaster.haml

%ul
  - foreach (var movie in ViewData.Model)
    _ Movie

The content rendered by the view in Listing 6 is plugged into the area of the master page marked by the underscore. The view loops through the movie records represented by the ViewData.Model property.

Notice the syntax _ Movie. You use this syntax to add a user control (partial) to a view. The syntax _ Movie adds a user control named _Movie.haml to the view. The _Movie.haml user control is contained in Listing 7.

Listing 7 -- \Views\Home\_Movie.haml

%div
  Title: 
  =movie.Title
  %br /
  Director: 
  =movie.Director
  %hr /

There are two special things that you should notice about the user control in Listing 7. First, notice that the name of the user control starts with an underscore _. That is a requirement.

Second, notice that the user control can use a variable from its parent view. The user control is using the movie variable that represents a particular Movie database record. The user control gets the movie variable from the view in Listing 6.

When you request the ShowMaster view, the page in Figure 5 is rendered. The content of the master page, the view, and the user controls are merged and rendered as a single page.

Figure 5 – ShowMaster view

clip_image008

Note: I could not figure out a way to selectively apply the Application.haml master page to only certain views. Therefore, I renamed the Application.haml file to xApplication.haml in the code download at the end of this tip so that the other views described in previous listings would not use the master page.

Summary

One of the greatest strengths of the ASP.NET MVC framework is its extensibility. There is almost always a way to modify any feature of the framework. The most dramatic way in which you can change the behavior of the ASP.NET MVC framework is to change its view engine.

In this tip, I demonstrated how to swap out the default Web Forms view engine for the NHaml view engine. I showed how you can use view data, master pages, and user controls with the NHaml view engine. And, I hope, I have given you a sense of the unlimited possibilities inherit in the ASP.NET MVC framework.

Download the Code

13 Comments

  • Sweet article dude.

  • I've used it once. To bad there is no syntax highlight but as far as a view engine goes is really sweet.

    And very agile. The only part missing was when trying to do like a
    #class1 class2
    usually a div with class1 is generated but in order to achieve the result I wanted I had to do like a #div{ class="class1 class2"}

    Also the partials I thought were reaallly useful and the conventions is easy to learn.

    Also AFAIK elements like %br %hr etc are automatically converted to
    without the need of %br / but since it doesn't hurt to use the / at the end guess there's not such a big deal.

  • Nice tutorial, thanx!
    But how can you keep default webforms view engine, and in controller/action set nhalm just for that particular view?

  • @lazer -- good to know about not needing to use the / at the end of self-closing tags. I'll have to try that.

  • @lazer

    You can handle multiple classes like so:

    .class1.class2

    Or,

    %span#foo.bar.baz

  • It's really good, but I miss intellisense a lot, for the scripting parts.

  • @hhrvoje - You need to add the followin line of code to a controller action method before it returns a view:

    this.ViewEngine = NHamlViewEngine.Instance;

    In this case, remove the registration of the NHaml Controller Factory from the Global.asax.

  • It's Really very nice

  • It's very nice and the syntax is terse.
    Just wondering whether it supports nested master pages/layouts like Web Forms view engine.

  • Nice! You know my take on the way views are currently written. This is much better IMHO.

  • Really nice syntax but what will happen to the concept of consistency in view design?
    Last thing asp.net wants is inconsistency and number of different methods of expressing views like we have in php etc. Where you can use simple php or smarty or many unknown templating engines for doing the same stuff. And using spaces as a part of syntax will not at all go well with accessibility.
    I hope finally we will stuck with 1 or 2 view engines which will satisfy our general needs.
    Anyhow, great post, really shows how extensible the asp.net mvc is.

  • Nice, but counter productive. No syntax highlighting, no intellisense, and can't be given to a designer for a design intergration.

  • Asp net mvc tip 35 use the nhaml view engine.. Bully :)

Comments have been disabled for this content.