ASP.NET MVC Tip #19 – Use the nVelocity View Engine
In this tip, I demonstrate how you can use the nVelocity view engine, instead of the normal Web Forms view engine, when displaying views from an ASP.NET MVC application.
By default, you build views for an ASP.NET MVC application by creating ASP.NET Web Form pages (.aspx files). You are not required to do this. If you prefer, you can swap out the Web Forms view engine and use an alternative view engine. In this tip, I demonstrate how you can use the nVelocity view engine.
Why would you want to use the nVelocity view engine instead of the normal Web Forms view engine? You might be motivated for a couple of different reasons. First, nVelocity is a port of the Java Apache Software Foundation Velocity project to the .NET framework. If you are migrating an existing Java application to .NET, and the existing application was written with the Velocity template engine, then using the nVelocity view engine can make the migration process much smoother.
Second, you might prefer the template syntax of nVelocity over the syntax used in a normal ASP.NET Web Forms page. The Velocity Template Language was designed specifically for building HTML pages. Velocity provides you with a very clean syntax for performing common operations such as iterating over a set of database records and displaying each record in an HTML page (think Domain Specific Language for HTML).
Configuring nVelocity for ASP.NET MVC
It took me quite a bit of time to figure out how to get nVelocity configured to work with ASP.NET MVC. The problem is that you must grab files from two different projects to get everything to work (and some of the assemblies are hiding in nested folders).
Here are the steps that I followed to get nVelocity to work:
Step 1:
Download and unzip the MvcContrib binaries from the following website:
http://www.CodePlex.com/MvcContrib
Step 2:
Download and unzip the Castle Project from the following website:
http://www.castleproject.org/castle/download.html
Step 3:
After you unzip the archive from step 2, navigate to the bin folder and unzip the external-dependencies.zip archive. This archive contains the nVelocity.dll assembly.
Step 4:
Create a new Visual Studio 2008 ASP.NET MVC Application
Step 5:
Add a reference to the MvcContrib.Castle assembly which you can find in the archive that you downloaded in Step 1 (The MvcContrib.Castle assembly is part of the MvcContrib project and not the Castle Project).
Step 6
Add a reference to the NVelocity assembly which you unzipped in Step 3.
Two big warnings. First, don’t use the nVelocity assembly located at http://nvelocity.sourceforge.net. If you do a search for nVelocity with a search engine, this is the first entry that appears. Unfortunately, this project has not been updated since 2003 and the nVelocity assembly is massively out of date. Use the nVelocity assembly from the Castle Project instead.
Second, make sure that you Unblock any files that you download before you unzip them. You can unblock a file by right-clicking the file, selecting Properties, and clicking the Unblock button. If you fail to unblock an archive, then you will encounter security issues when you attempt to use files from the archive within Visual Studio.
Using the nVelocity View Engine
After you complete the steps in the previous section, you are ready to start using the nVelocity view engine. There are two ways that you can indicate to the ASP.NET MVC framework that you want to use nVelocity instead of the normal Web Forms view engine.
First, you can modify a controller’s ViewEngine property within a controller action before returning a view. For example, the HomeController in Listing 1 uses nVelocity for its Index() action.
Listing 1 – HomeController.vb (VB.NET)
Imports System.Web.Mvc
Namespace Tip19.Controllers
Public Class HomeController
Inherits Controller
Private _dataContext As New MovieDataContext()
Public Function Index() As ActionResult
Me.ViewEngine = New MvcContrib.Castle.NVelocityViewFactory()
Return View(_dataContext.Movies)
End Function
End Class
End Namespace
Listing 1 – HomeController.cs (C#)
using System.Web.Mvc;
using Tip19.Models;
namespace Tip19.Controllers
{
public class HomeController : Controller
{
private MovieDataContext _dataContext = new MovieDataContext();
public ActionResult Index()
{
this.ViewEngine = new MvcContrib.Castle.NVelocityViewFactory();
return View(_dataContext.Movies);
}
}
}
If you want to use nVelocity for only certain pages within your web application, then setting the ViewEngine property is an easy way to switch view engines. However, if you want to use nVelocity for all of your views, then you should consider creating a custom Controller Factory. The custom Controller Factory in Listing 2 changes the default view engine to nVelocity.
Listing 2 – VelocityControllerFactory.vb (VB.NET)
Imports System
Imports System.Web.Mvc
Public Class VelocityControllerFactory
Inherits DefaultControllerFactory
Protected Overrides Function GetControllerInstance(ByVal controllerType As Type) As IController
Dim controller As IController = MyBase.GetControllerInstance(controllerType)
Dim velocityController As Controller = TryCast(controller, Controller)
If velocityController IsNot Nothing Then
Dim context = New ControllerContext(Me.RequestContext, velocityController)
velocityController.ViewEngine = New MvcContrib.Castle.NVelocityViewFactory()
End If
Return controller
End Function
End Class
Listing 2 – VelocityControllerFactory.cs (C#)
using System;
using System.Web.Mvc;
namespace Tip19.Controllers
{
public class VelocityControllerFactory : DefaultControllerFactory
{
protected override IController GetControllerInstance(Type controllerType)
{
IController controller = base.GetControllerInstance(controllerType);
Controller velocityController = controller as Controller;
if (velocityController != null)
{
var context = new ControllerContext(this.RequestContext, velocityController);
velocityController.ViewEngine = new MvcContrib.Castle.NVelocityViewFactory();
}
return controller;
}
}
}
In order to use a custom Controller Factory, you must register the factory within your application’s Global.asax file. The modified Global.asax file in Listing 3 contains a call to the SetControllerFactory() method within its Application_Start() method.
Listing 3 – Global.asax.vb (VB.NET)
Imports Tip19
Public Class GlobalApplication
Inherits System.Web.HttpApplication
Shared Sub RegisterRoutes(ByVal routes As RouteCollection)
routes.IgnoreRoute("{resource}.axd/{*pathInfo}")
' MapRoute takes the following parameters, in order:
' (1) Route name
' (2) URL with parameters
' (3) Parameter defaults
routes.MapRoute( _
"Default", _
"{controller}/{action}/{id}", _
New With {.controller = "Home", .action = "Index", .id = ""} _
)
End Sub
Sub Application_Start()
ControllerBuilder.Current.SetControllerFactory(GetType(VelocityControllerFactory))
RegisterRoutes(RouteTable.Routes)
End Sub
End Class
Listing 3 – Global.asax.cs (C#)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using Tip19.Controllers;
namespace Tip19
{
public class GlobalApplication : System.Web.HttpApplication
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = "" } // Parameter defaults
);
}
protected void Application_Start()
{
ControllerBuilder.Current.SetControllerFactory(typeof(VelocityControllerFactory));
RegisterRoutes(RouteTable.Routes);
}
}
}
After you register the VelocityControllerFactory, all controllers in your MVC application will use the nVelocity view engine by default. You no longer need to modify the ViewEngine property within each and every controller action method.
Creating an nVelocity View
You create an nVelocity view by creating a .vm file. Visual Studio does not contain a template for Velocity views. You can create a Velocity view by creating an HTML page and changing its extension from .htm to .vm.
For example, the view in Listing 4 contains a Velocity template that displays all of the movies passed from the HomeController from Listing 1.
Listing 4 – Views\Home\Index.vm
<!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>Untitled Page</title>
</head>
<body>
#foreach( $movie in $Viewdata.Model )
<li><a href="/Home/Edit/$movie.Id">$movie.Title</a></li>
#end
</body>
</html>
The view in Listing 4 takes advantage of the Velocity template language to display the movies. Notice that a for…each block is created by using the Velocity directives #foreach and #end. Notice that you use a $ to mark something as a variable. Therefore, you can refer to ViewData.Model with the expression $Viewdata.Model. Velocity is not case-sensitive.
There is a complete reference to the Velocity language located at the Apache Software Foundation website. This website also has a quick guide to Velocity. See:
http://velocity.apache.org/engine/releases/velocity-1.5/vtl-reference-guide.html
http://velocity.apache.org/engine/releases/velocity-1.5/user-guide.html
Summary
In this tip, I demonstrated how you can use the nVelocity template engine with an ASP.NET MVC application. I showed two methods of swapping out the default Web Forms view engine. I showed how you can specify a particular view engine for a particular controller action and I showed how you can specify a particular view engine for all controller actions.
I’m certainly not recommending that you should abandon the Web Forms view engine in favor of the nVelocity view engine. The real goal of this tip was to demonstrate the flexibility of ASP.NET MVC. If you don’t like anything about the ASP.NET MVC framework, you always have the option of changing it.