Entries:
Comments:
Posts:

Loading User Information from Channel 9

Something went wrong getting user information from Channel 9

Latest Achievement:

Loading User Information from MSDN

Something went wrong getting user information from MSDN

Visual Studio Achievements

Latest Achievement:

Loading Visual Studio Achievements

Something went wrong getting the Visual Studio Achievements

Developer Review - Four ASP.NET MVC View Engines

Introduction

In this Developer Review, we evaluate four view engines available for use with ASP.NET MVC. First, we discuss the role a view engine plays in a website built with ASP.NET MVC, then we provide details about the four view engines in order to help you decide which one suits your needs.

Jason Haley

http://jasonhaley.com/blog/

Source Code: Download in Branches/Playground directory

 

What Does a View Engine Do?

When we refer to a view engine in ASP.NET MVC, we are talking about three pieces of functionality:

·         A template locator/provider (implementation of IViewEngine)

·         A template that can render itself (implementation of IView)

·         A template engine that can parse and compile the view file syntax into executable code

Combining these three pieces, a view engine provides your controllers with the ability to translate views into Html.

Why Use an Alternate View Engine?

Though the view engine that ships with ASP.NET MVC has all the functionality you need to create views for just about any website project, it is also easily replaced.

As with choosing a programming language in .Net, there are many reasons why you may choose one view engine over another:

Syntax
ASP.NET MVC’s default view syntax is sometimes described as “tag soup.” This is due to the mix of all the  <%%> tags along with the Html markup and causes some developers to feel like the view is messy.

Skillset/background
Many developers have already used the Castle Monorail MVC framework and are experiences with the view engines provided for that framework. Accordingly, it makes sense to leverage that experience by using a similar view engine in ASP.NET MVC.

Productivity
For you, productivity may mean quick and easy to learn syntax or it may mean terse and less code. Depending on which is right for you, you may choose a different view engine. 

Specialized Problem Domains
Some view engines use a DSL-like-language to represent the view, which may fit well within your environment. 

Testability
View engines that don’t depend on the System.Web.UI.Page are easier to test than the default ASP.NET MVC view engine, which uses Page for a base class of its view implementation.

Division of labor
If you have designers working on the views, or just want minimal logic in your views, you should choose a view engine that easily mixes with Html.

Feature Comparison

View Language Features

Feature

WebFormViewEngine

Spark

NHaml

Razor

Multi Line Code Blocks

X

X

X

X

Inline Expression

X

X

X

X

Local Functions

X

X

 

 

Local Variables

X

X

X

X

Global variables

 

X

X

 

Conditional Output

X

X

X

X

Support for Multiple Level Conditions

X

X

X

X

Loops

X

X

X

X

Html Encoding Shortcuts

X

(ASP.NET 4.0)

X

X

 

Global Setting for Html Encoding

 

X

X

   X

Limited Escape to prevent Html Encoding

 

View Language Convenience Features

Feature

WebFormViewEngine

Spark

NHaml

Razor

Global Namespace Imports

X

X

X

X

Import Namespaces

X

X

 

X

 

Master Page Features

Feature

WebFormViewEngine

Spark

NHaml

Razor

Single View Master Page

X

X

 

X

Global Master Page

 

X

X

X

Content Placeholders

X

X

 

X

Special Syntax for Partial Views

 

X

X

 

 

Other Features

Feature

WebFormViewEngine

Spark

NHaml

Razor

Support for Editor Templates

X

X

 

X

Visual Studio Integration

 X

VS 2008/VS 2010 Built in

X

VS 2008/VS 2010Addins

X 

VS 2008 Addin

 X

VS 2010 - More coming soon

Supports MonoRail

 

X

X

X

Desired Features

I created the following list of features after porting the views from the NerdDinner (http://nerddinner.codeplex.com/) example to Spark, NHaml, and Razor. The features mentioned are  the different features I had to learn in order to convert the views to the different view engines. I’ve grouped the features into four areas: view language, view language convenience, master page features, and   miscellaneous features.

View Language Features

Multi Line Code Blocks

Allows you to write multiple lines of code in your views. A related feature is local variables.

Inline Expression

An Inline Expression allows you to put a code expression inside static content in the view.

Local Functions

Local Functions provide the ability to create functions  that can be called in multiple view locations.  A related feature is Multi Line Code Blocks.

Local Variables

Provide a variable that is scoped to the view.

Global Variables

Allows you to provide variables available to all views in your site.

Conditional Output

Allows you to use if/else statements to control the output.

Support for Multiple Level Conditionals

Provides the ability to nest if/then statements.  Conditional output is a related feature.

Loops

Allows you to use loop structures to provide repetitive data output.

Html Encoding Shortcuts

Provides shortcuts to ensuring returned output is HtmlEncoded.

Global Setting for Html Encoding

Provides the ability to automatically HtmlEncode returned content.

View Language Convenience Features

Import Namespaces

Allows you to import a namespace for a given view so you don’t need to type the fully qualified name of your objects..

Global Namespace Imports

Ability to set a namespace import for all views in one location.

Master Page Features

Single View Master Page

Provides the ability to set a master page for a single view.

Global Master Page

Ability to have a master page that is used for all views by default.

Content Placeholders

This feature has two parts. One part allows you to put placeholders in your master page. The second part allows you to specify the content to put in those placeholders. This means a view can optionally populate multiple content placeholders in the master page.

Special Syntax for Partial Views

Provides view language syntax to indicate where a partial view should be output. This is an alternative  to the MVC’s framework Html helper extension (Html.RenderPartial).

Other Features

Support for Editor Templates

Editor Templates are an MVC 2 feature and allow you to declare what editor template you want loaded on your model classes. Editor Templates are a feature of the ASP.NET MVC framework and are not a feature of the view engine. Not all view engines, however, are able to parse the syntax used to make this work.

Visual Studio Integration

Visual Studio integration includes tooling for creating views, as well as IntelliSense and keyword coloring—things we take for granted most of the time.

Support of Other MVC Frameworks

Ability to use the same view engine with other .NET MVC Frameworks (like Castle’s MonoRail).

View Engines Evaluated in this Developer Review

ASP.NET MVC Default View Engine (WebFormViewEngine)

Website

http://www.asp.net/mvc

Download site

http://www.asp.net/downloads

License

Microsoft Public License (MS-PL)

Last Release

MVC 2.0 (Last Release), MVC 3 Preview 1

Creator(s)

ASP.NET MVC Team at Microsoft

Support Forum

http://forums.asp.net/1146.aspx

Languages Supported

C#, Visual Basic

ASP.NET MVC Versions

1.0, 2.0, 3 (Preview 1)

Spark View Engine

Website

http://sparkviewengine.com/

Download site

http://sparkviewengine.codeplex.com/

License

Apache License, Version 2.0

Last Release

Spark v1.1 (March 11, 2010)

Creator(s)

Louis DeJardin

Support Forum

http://groups.google.com/group/spark-dev?pli=1

Languages Supported

C#, Visual Basic, Iron Python, Iron Ruby

ASP.NET MVC Versions

1.0, 2.0

 

NHaml View Engine

Website

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

Download site

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

License

MIT License

Last Release

Nhaml-2.0-beta-4 (August, 20, 2010)

Creator(s)

Andrew Peters

Support Forum

http://groups.google.com/group/nhaml-users

Languages Supported

C#, Visual Basic, Iron Ruby, Boo, F#

ASP.NET MVC Versions

1.0, 2.0

Razor

Website

http://www.asp.net/mvc and http://www.asp.net/WebMatrix

License

 

Last Release

Pre-releases: WebMatrix Beta and MVC 3 Preview 1

Creator(s)

ASP.NET MVC Team at Microsoft

Support Forum

http://forums.asp.net/1146.aspx

Languages Supported

C#, Visual Basic

ASP.NET MVC Version

3 (Preview 1)

ASP.NET MVC Default View Engine (aka WebFormViewEngine)

If you’ve written any views in MVC, you’ve used the WebFormViewEngine view engine at one point or another. The syntax for writing views with this engine is the same syntax ASP.NET Web Forms uses for .aspx pages.

The default view engine used by ASP.NET MVC is powerful, mature and can do everything you need to do in a view – after all it stands on the shoulders of ASP.NET. Due to its IViewEngine implementation being in the class named WebFormViewEngine, the ASP.Net MVC default view engine is sometimes called the WebFormViewEngine.

The WebFormViewEngine is different than the other view engines in this review in that it extends ASP.NET’s Page class for its views. This allows the view engine to use a lot of the ASP.NET infrastructure to do the heavy lifting of parsing and compiling the view content.

The file extensions used are also borrowed from ASP.NET: .aspx for views, .ascx for partial views (and editor templates), and .master for master pages. 

The following is a screen shot of a view written with the default ASP.NET MVC view engine:

image
Screenshot 1.  NerdDinners Dinner/Index Views using default view engine

 

History

The WebFormViewEngine’s history starts with ASP.NET MVC, which hit CTP in December 2007. Currently, it is the only view engine that ships with ASP.NET MVC.  This view engine extends ASP.NET’s Page object to provide the view abstraction to MVC.  This allows views to be written in the same web forms syntax used in ASP.NET web pages. The server-side escape syntax used by the view engine (<%%>) dates back to Classic ASP (that is, before .Net). 

The base classes used by the WebFormViewEngine—ViewPage, ViewMasterPage, and ViewUserControl—are derived from the ASP.NET relatives Page, MasterPage, and UserControl, respectively, thus providing a mature rendering capability to the view.

Key Features

The WebFormViewEngine supports fourteen  desired features.

Feature

Notes

Multi Line Code Blocks

 

Inline Expression

 

Local Functions

 

Local Variables

 

Conditional Output

 

Support for Multiple Level Conditionals

 

Loops

 

Html Encoding Shortcut

Only when using ASP.NET 4.0

Global Namespace Import

Add in the web.config

Import Namespace

 

Single View Master Page

2 Options: Page Directive or Change in the Controller

Content Placeholders

 

Support for Editor Templates

 

Visual Studio Integration

Best support of all view engines

Getting Started

If you have ASP.NET MVC installed, you already have the WebFormViewEngine installed (if needed, download the ASP.NET MVC framework from http://www.asp.net/downloads).

Dependencies

The WebFormViewEngine is included in the System.Web.Mvc.dll, so the view engine is versioned with the ASP.NET MVC framework you reference. However, some of the features of the WebFormViewEngine are dependent on the version of the .Net framework/ASP.NET you are using. For example, if you are using .Net 3.5, to Html encode an output value you need to use syntax like the following:

image
Figure 1.  ASP.NET Html Encode

If you are using .Net 4.0, you can use the new “Code Nugget” syntax to do the same thing:

image
Figure 2. ASP.NET 4.0 Html Encoding Syntax

Feature Syntax

Since syntax is one of the main reasons you may want to use an alternative view engine, I have included some examples of the corresponding key features. This is not meant to be a language reference; rather, it is included to help you get a feel for how you may implement a view using the different view engines:

Example of a Multi-Line Code Block

<%

           string message = "The time is: {0}";

           string timeString = DateTime.Now.ToShortTimeString();

           string output = string.Format(message, timeString);

  %>

  The result from serverside code is: <%=output %>

 

Code Sample 1. Mult-Line Code Block - ASPX

Example of Inline Expression

 
<script src="<%=Url.Content("~/Scripts/MSAjaxHistoryBundle.js")%>" 
    type="text/javascript"></script>

 

Code Sample 2.  Inline C# Code - ASPX

Example of a Local Function

<script runat="server">

      string FunctionCallOnServerSide()

    {

           return "Hello World!";

    }

  </script>

  <div>

    This is client side html

    Server Says: <%=FunctionCallOnServerSide() %>

    and more client side html

  </div>

 

Code Sample 3.  Local Function - ASPX

Example of a Local Variable

<%

           string message = "Hello World";
%>

  The result message is: <%= message %>

 

Code Sample 4. Local Variable Usage - ASPX

Example of Conditional Output

<strong>Who's Coming:</strong>

  <% if (Model.RSVPs.Count == 0){%>

    <span>No one has registered.</span>

  <% } %>

 

Code Sample 5.  Conditional Output - ASPX

Example of Multi Level Condition Output

<% if (Request.IsAuthenticated) { %>

  <% if (Model.IsHostedBy(Context.User.Identity.Name)) { %>

    <p>You are the host for this event!</p>

  <% } else { (Model.IsUserRegistered(Context.User.Identity.Name)) { %>
    <p>You are registered for this event!</p>   
  <% } %>   <% } else { %>

  <strong>RSVP for this event:</strong>

  <% } %>

 

Code Sample 6.  Multi-Level Condition Output - ASPX

Example of For Loop

<% foreach (var dinner in Model) { %>
  <li>
    <%: Html.ActionLink(dinner.Title, "Details", 
           new { id=dinner.DinnerID }) %>
  </li>
<% } %>

 

Code Sample 7.  For Loop - ASPX

Example of Html Encoding Shortcut

<%: dinner.Address + " " + dinner.Country %>

 

Code Sample 8.  Html Encoding Shortcut

Example of Global Namespace Import in Web.Config

<pages controlRenderingCompatibilityVersion="3.5" clientIDMode="AutoID">

         <namespaces>

              <add namespace="System.Web.Mvc" />

              <add namespace="System.Web.Mvc.Ajax" />

 

Code Sample 9.  Global Namespace Import - ASPX

Example of Importing a Namespace in a View

<%@ Import Namespace=”NerdDinner.Helpers" %>

 

Code Sample 10. Namespace Import - ASPX

Example of Setting Master Page in View’s Page Directive

<%@ Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master" 
  Inherits="System.Web.Mvc.ViewPage" %>

 

Code Sample 11.  Setting MasterPageFile attribute in Page Directive - ASPX

Example of Changing Master Page in Controller:

public ActionResult About() {
   var result = View();
   result.MasterName = "AlternateMaster";     
   return result;
}

 

Code Sample 12.  Setting MasterName Property of a View - ASPX

Example of Master Page with Content Placeholders

<head id="Head1" runat="server">
   <title>
      <asp:ContentPlaceHolder ID="TitleContent" runat="server" />
   </title>
   <asp:ContentPlaceHolder ID="HeadContent" runat="server" />
</head>    

Code Sample 13.  Master Page with ContentPlaceholders - ASPX

Example of View with Multiple Content Elements

<asp:Content 
   ID="TitleArea" 
   ContentPlaceHolderID="TitleContent" 
   runat="server">
     About
</asp:Content>
<asp:Content 
   ID="HeadArea" 
   ContentPlaceHolderID="HeadContent" 
   runat="server">
   <script 
     src="<%=Url.Content("~/Scripts/jquery-1.4.1.min.js")%>" 
     type="text/javascript"></script>
</asp:Content>

 

Code Sample 14. View with Content Elements - ASPX

Visual Studio Integration

Being the first view engine for ASP.NET MVC also means that the WebFormViewEngine has an advantage over other view engines when it comes to Visual Studio tooling and support.   Once you install ASP.NET MVC, you have the default view engine integrated into Visual Studio – which provides a lot of tooling for your views.

image
Figure 1.  Add View Dialog

The Visual Studio tooling provides an Add View Dialog (shown above) when you create a new view, which provides the following features:

·         Ability to specify whether the view is a partial view or normal view

·         Choice of the type of view model you want

·         Option to choose a T4 template for generating the view content or just create an empty view

·         Option to use a master page and set the content placeholder for the view’s content

IntelliSense Support

Visual Studio provides complete IntelliSense support for views using the WebFormViewEngine, including support for the directives used at the top of the page (page settings, namespace imports, etc.) and usage documentation as you type, as well as all other .aspx and .ascx productivity enhancements added by Visual Studio over the years, including ASP.NET MVC, HTML markup, and JavaScript Snippets (new in VS 2010).


Figure 2. Page Directive IntelliSense image


Figure 3. Usage Documentation IntelliSenseimage


Figure 4.  ASP.NET MVC Snippet for Action Link Startimage


Figure 5. ASP.NET MVC Snippet for Action Link Resultimage

Getting Support

The WebFormViewEngine is part of the ASP.NET MVC framework and is supported the same way as the framework. The primary support forum for the ASP.NET MVC framework can be found at: http://forums.asp.net/1146.aspx

ASP.Net Default View Engine Strengths

·         It is included with ASP.NET MVC

·         It is supported along with the ASP.NET MVC framework

·         It is easy to learn

·         Web Form developers can utilize their web form development experience to get started with MVC views

ASP.Net Default View Engine Weaknesses

·         Hard to test due to a dependency on Page

·         The syntax can lead to views becoming “tag soup”

Spark View Engine

The Spark view engine was designed to mix the code into the flow of the html, which leads to nicer looking views without all the escape syntax that dominates the WebFormViewEngine’s syntax.

Spark has been around for more than two years now and has a lot of features you won’t find in the default view engine. Unlike the WebFormViewEngine, Spark has its own view class and doesn’t extend the ASP.NET Page class. Spark also works with both ASP.NET MVC and Castle MonoRail MVC Framework.

The Spark view engine differs from the other view engines because it mixes its language syntax in with the elements of your view. The language constructs exist mostly as elements and attributes. For example, there is an <if> element and a <for> element, and partial views can also be represented as an element.

The file extension used for views, partial views, and layouts (master pages) is .spark

Below is a screen shot of a view written using the Spark view engine:

image

Screenshot 2.  NerdDinners Dinner/Index View in Spark

History

Louis DeJardin began developing the Spark view engine in May 2008, soon after reading a blog entry by Phil Haack (Code Based Repeater for ASP.NET MVC). Louis designed and wrote the view engine from ground up (it is not a port of another view engine or language) in order to build a view syntax able to seamlessly mix the code into the Html.

Key Features

Spark is the only view engine of the four that supports all of the features on my desired feature list.

Feature

Notes

Multi Line Code Blocks

 

Inline Expression

 

Local Functions

Called ‘Macros’, limited to functions that return strings

Also supports global functions.

Local Variables

 

Global Variables

 

Conditional Output

 

Support for Multiple Level Conditionals

 

Loops

 

Html Encoding Shortcut

 

Global Setting for Html Encoding

 

Import Namespaces

 

Global Namespace Imports

Add in the web.config or _global.spark file

Single View Master Page

 

Global Master Page

 

Content Placeholders

 

Special Syntax for Partial Views

If partial view file begins with ‘_’ can use the name as an element in the view.

Support for Editor Templates

 

Visual Studio Integration

Add-ins exist for VS 2008 and VS 2010

Support for Other MVC Frameworks

 

 

Getting Started

Spark is available for download at http://sparkviewengine.codeplex.com/. After you have downloaded and extracted the binaries, add Spark as a view engine in your ASP.NET MVC project by performing the following steps:

1.       Set a reference to the Spark.dll and Spark.Web.Mvc.dll libraries included in the release download.

2.       Open the Global.asax.cs file and add a new SparkViewFactory to the ViewEngines.Engines collection:

void Application_Start()

{

       RegisterRoutes(RouteTable.Routes);

 

       ViewEngines.Engines.Add(new SparkViewFactory());

}

 

3.       In your web.config file, add a section to your configSections for the SparkSectionHandler as shown below:

<configuration>

  <configSections>

    <section name="spark" type="Spark.Configuration.SparkSectionHandler, Spark"/>

 

4.       Add the <spark> section to your web.config file. I put mine just after the </connectionStrings> element. Below is the configuration section I used to port the NerdDinner project to Spark.

<spark>

    <compilation debug="true" defaultLanguage="CSharp" />

    <pages automaticEncoding="true" >

      <namespaces>

        <add namespace="System"/>

        <add namespace="System.Collections.Generic"/>

        <add namespace="System.Linq"/>

        <add namespace="System.Web"/>

        <add namespace="System.Web.Mvc"/>

        <add namespace="System.Web.Mvc.Html"/>

      </namespaces>

    </pages>

  </spark>

5.       Change the settings as necessary (check the documentation for the options that apply to you).

Dependencies

For Spark to work as a view engine in your ASP.NET MVC project, you need references to the Spark.dll and Spark.Web.Mvc.dll

Feature Syntax

The following are examples for the key features listed above:

Example Using the # Statement for Escaping Multiple Lines of Code

#      string message = "The time is: {0}";

#      string timeString = DateTime.Now.ToShortTimeString();

#      string output = string.Format(message, timeString);

 

The result from serverside code is: ${output}

 

Code Sample 15. Using the # Statement to Escape Code -Spark

Example Using ${ } for an Inline Expression

<script src="${ Url.Content("~/Scripts/MSAjaxHistoryBundle.js") }"

    type="text/javascript"></script>

 

Code Sample 16. Using Inline Escape -Spark

One drawback to using the ${} syntax is that it will fail if the expression returns null. In order to protect against the possibility of an expression returning null, you can use the $!{} expression.

Example Using !${} to Output an Expression that May Return Null

<span class="fn nickname">$!{ Model.RSVPs.FirstOrNull() }</span>

 

Code Sample 17. Using Inline Escape When Expression Maybe Null -Spark

Example of a Local Function (Macro) in Spark:

<macro name="FunctionCallOnServerSide" message="string">

       <b>${message}</b>   

</macro>

 

<div>

       This is client side html

       Server Says: ${ FunctionCallOnServerSide("OutputMessage") }

       and more client side html

</div>

 

Code Sample 18. Declaring and Using a Macro -Spark

Example of Creating and Using a Local Variable

<var RSVPs = "Model.RSVPs.Reverse()"/>

${RSVPs.Count().ToString() }

 

Code Sample 19. Local Variable Usage -Spark

Example of Creating and Using a Global Variable

<global version="0.01F" type="float" />

${version + 1}

 

Code Sample 20. Global Variable Usage -Spark

Example of Conditional Output - If/Else Element

<strong>Who's Coming:</strong>

<if condition="Model.RSVPs.Count == 0">

    <span>No one has registered.</span>

</if>

<else>

    ... other markup here ...

</else>

 

Code Sample 21. If/Else Element Usage-Spark

Example of Conditional Output - if Attribute

<strong>Who's Coming:</strong>

<span if="Model.RSVPs.Count == 0">No one has registered.</span>

<else>

    ... other markup here ...

</else>

 

Code Sample 22. If Attribute Usage -Spark

Example of Multi Level Condition Output

<if condition="Request.IsAuthenticated">

  <if condition="Model.IsHostedBy(Context.User.Identity.Name)">

    <p>You are the host for this event!</p>

  </if>

  <else if="Model.IsUserRegistered(Context.User.Identity.Name)">

    <p>You are registered for this event!</p>

  </else>

<else>

  <strong>RSVP for this event:</strong>

</else>

 

Code Sample 23. Multi-Level Condition Output - Spark

Example of Loop - For Element

<ul class="upcomingdinners">

    <for each="var dinner in Model">

       <li>

           !{ Html.ActionLink(dinner.Title, "Details", new { id=dinner.DinnerID }) }

       </li>

    </for>

</ul>

 

Code Sample 24. For Element Usage -Spark

Example of Loop -  each Attribute

<ul class="upcomingdinners">

    <li each="var dinner in Model">    

       !{ Html.ActionLink(dinner.Title, "Details", new { id=dinner.DinnerID }) }

    </li>

</ul>

 

Code Sample 25.  Each Attribute Usage -Spark

Global Html Encoding Setting

For html cncoding you can set the automaticEncoding flag in the spark section of your web.config file to turn html encoding on by default. This will cause every ${expr} expression evaluation to be Html encoded. 

If you need to specify an expression to not be Html encoded, use the !{ expr } syntax.

  <spark>

    <compilation debug="true" defaultLanguage="CSharp" />

    <pages automaticEncoding="false" >

 

Code Sample 26.  AutomaticEncoding Attribute Set in Web.Config -Spark

Html Encoding Inline

Spark provides a utility method that will Html Encode expressions called H( ). However, I recommend having automaticEncoding on via the global setting and using the !{ } syntax for when you don’t want to include Html Encoding.

Example of Global Namespace Import in Web.Config

  <spark>

    <compilation debug="true" defaultLanguage="CSharp" />

    <pages automaticEncoding="false" >

      <namespaces>

        <add namespace="System"/>

        <add namespace="System.Collections.Generic"/>

 

Code Sample 27. Global Namespace Import -Spark

Example of Importing  a Namespace

<use namespace="NerdDinner.Helpers" />

 

Code Sample 28. Adding a Namespace Import - Spark

Global Master Page Support

Spark includes a site-wide master page (or layout), which allows you to have all views use a master page without having to specify the name for each of the views.

In order to create a global master page/layout, create an Application.spark file in the Views/Layouts folder or the Views/Shared folder.

You can also create a layout for a specific controller. To do so, create a layout with the same name as the controller.

Example of Setting Master Page in a View

<use master="AlternateMaster" />

 

Code Sample 29. Master Layout Assignment -Spark

Example of Master Layout with Multiple Content Elements

<head>
    <title><use content="TitleContent" /></title>

    <use content="HeadContent" />

</head>   

Code Sample 30. Master Layout with Content Elements -Spark

Example of a View with Multiple Content Elements

<content name="TitleContent">

  Upcoming Nerd Dinners

</content>

 

<content name="HeadContent">

  # Html.RenderPartial("Masthead", false);

</content>

 

This text will be in the view's main content … notice this is not in a content element.

 

Code Sample 31.  View with Multiple Content Elements -Spark

Special Partial View Syntax

Spark provides a special partial view syntax that,flows better than the HtmlHelper syntax. 

If the name of your partial view file begins with an underscore character, you can use an element in your content to represent the partial view (minus the underscore) . For example, in my NerdDinner Spark port, there is a layout named _LoginStatus.spark. This allows me to use the element <LoginStatus /> to represent the output location I want for the contents of that partial view. 

Visual Studio Integration

Since Spark is a third party view engine, the Visual Studio tooling isn’t as good as the WebFormViewEngine. This means that you currently don’t get the functionality provided by the Add View dialog described in the WebFormViewEngine section and so are stuck working with text or html looking files.

IntelliSense Support

For Visual Studio 2008, there is an msi installer included for the 3-9-2009 Build available on the http://sparkviewengine.com/download site.

For Visual Studio 2010, there is a Visual Studio Addin available in Visual Studio Gallery: SparkSense.

Getting Support

For an open source project, Spark is pretty well documented. The documentation can be found on the project site at http://sparkviewengine.com/documentation.

The Spark View Engine also has a Google Group where you can get answers to your questions. Check it out at http://groups.google.com/group/spark-dev.

The Issue Tracker is available on the on the CodePlex site: http://sparkviewengine.codeplex.com/workitem/list/basic.

Spark View Engine Strengths

·         Syntax produces clean views

·         Views don’t use the Page class and so are easier to test

·         Well documented with a lot of samples included in the download

·         Supports other MVC frameworks

Spark View Engine Weaknesses

·         Visual Studio tooling isn’t as good as the default view engine

·         Advanced usage of some features can make the views harder for a developer to follow

NHaml View Engine

The NHaml (pronounced enamel) view engine is an implementation of the Rails Haml view engine, and its syntax is an abstraction of usual tag based XHTML syntax used by most view engines.  As you can see in the screen shot below, it takes only 19 lines in NHaml to create the same view created with 42 lines in the WebFormViewEngine and Spark view engines. A couple of other differences are that the syntax is white space sensitive and you don’t have to set the type of the view model (it figures it out for you).

The file extension used for views, partial views and layouts (master pages) is .haml

Below is a screen shot of a view written using the NHaml view engine:

image

Screenshot 3.  NerdDinners Dinner/Index View in NHaml

History

Haml was started in May 2006 by Hampton Catlin and from what I can find on the internet, Andrew Peters introduced NHaml to the world in December 2007.  The syntax is pretty much the same as Haml, but the parsing/compiling was all written from the ground up.  Like Spark, NHaml does not use the ASP.NET’s Page for its view, it has its own implementation.

Key Features

NHaml supports 14 features from the desired feature list.

Feature

Notes

Multi Line Code Blocks

 

Inline Expression

 

Local Variables

 

Global Variables

 

Conditional Output

 

Support for Multiple Level Conditionals

 

Loops

 

Html Encoding Shortcut

 

Global Setting for Html Encoding

 

Global Namespace Imports

Have to add all namespace imports to the web.config

Global Master Page

 

Special Syntax for Partial Views

 

Visual Studio Integration

Add-in exist for VS 2008

Support for Other MVC Frameworks

 

Getting Started

NHaml is available for download from the project’s website at http://code.google.com/p/nhaml/downloads/list. After you have downloaded the release package and extracted its contents, you can add the NHaml view engine to your ASP.NET MVC project by performing the following steps:

1.       Set a reference to the NHaml.dll and NHaml.Web.Mvc.dll libraries included in the release download.

2.       Open the Global.asax.cs file and add a new NHaml.Web.NHamlMvcViewEngine to the ViewEngines.Engines collection:

void Application_Start()

{

    RegisterRoutes(RouteTable.Routes);

   

    ViewEngines.Engines.Add(new NHaml.Web.Mvc.NHamlMvcViewEngine());

}

 

3.       In your web.config file, add a section to your configSections for the NHamlConfigurationSection handler as shown below:

<configuration>

  <configSections>

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

 

4.       Add the <nhaml> section to your web.config file. As mentioned in the Spark setup, I put mine right after the </connectionStrings> element. Below is the section I used to port the NerdDinner project to NHaml—notice it has more assemblies and namespace declarations than the one provided in the Spark setup:

<nhaml autoRecompile="true" templateCompiler="CSharp4" encodeHtml="true" useTabs="true" indentSize="4">

       <assemblies>

         <clear/>

         <add assembly="System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/>

         <add assembly="NerdDinner, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>

         <add assembly="DDay.iCal, Version=0.80.0.0, Culture=neutral, PublicKeyToken=1790ba318ebc5d56" />

         <add assembly="Elmah, Version=1.0.10617.0, Culture=neutral, PublicKeyToken=null" />

         <add assembly="DotNetOpenAuth, Version=3.4.4.10162, Culture=neutral, PublicKeyToken=2780ccd10d57b246" />

         <add assembly="OpenSearchToolkit, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>

       </assemblies>

       <namespaces>

         <clear/>

         <add namespace="System.Collections"/>

         <add namespace="NerdDinner" />

         <add namespace="NerdDinner.Helpers" />

         <add namespace="NerdDinner.Models" />

         <add namespace="DotNetOpenAuth.OpenId.RelyingParty" />

         <add namespace="DotNetOpenAuth.Mvc" />

         <add namespace="System.Web.Mvc.Html" />

         <add namespace="System.Web.Mvc" />

         <add namespace="System.Globalization" />

         <add namespace="System.Web.Mvc.Ajax" />

         <add namespace="System.Linq" />

       </namespaces>

  </nhaml>

 

5.       Check the configuration documentation at http://code.google.com/p/nhaml/wiki/Configuration to determine your project needs.

Dependencies

In order to be used, the NHaml view engine requires that the following two dll’s be referenced in your MVC project: NHaml.dll and NHaml.Web.Mvc.dll.

Feature Syntax

Whitespace is important and represents the hierarchy of the final XHTML document being marked up in the view in addition to the scoping of things such as for loops and if statements.

Example of a Multi-Line Code Block

- string message = "The time is: {0}";

- string timeString = DateTime.Now.ToShortTimeString();

- string output = string.Format(message, timeString);

 

The result from serverside code is:

       =output

 

Code Sample 32. Using CodeBlocks - NHaml

Inline Expression

To indicate which code should be evaluated in NHaml, you use either universal interpolation or evaluate output. The Universal Interpolation allows you to leave expressions to be evaluated in the middle of a line even though the evaluate output is typically at the beginning of a line.

Example of the #{ } Syntax to Evaluate Inline Code

%a { class="feed" href=#{Url.Action("iCalFeed", "Services", null, "webcal")} }

 

Code Sample 33. Using Inline Expression - NHaml

Example of the = Syntax to Evaluate and Output Code

=dinner.Address + " " + dinner.Country

 

Code Sample 34. Using Inline Expression2- NHaml

Example of Creating and Using a Local Variable

- string message = "The time is a message";

 

The result from serverside code is:

    =message

 

Code Sample 35. Local Variable Usage - NHaml

Example of a Creating and Using Global Variable

^ string PageTitle = "";

      

  - if (PageTitle != "")

    %title=PageTitle

 

Code Sample 36. Global Variable Usage - NHaml

Example of Conditional Output

%strong Who's Coming:

- if (Model.RSVPs.Count == 0)

    No one has registered.

 

Code Sample 37. Conditional Output - NHaml

Example of Multi Level Condition Output

- if (HttpContext.Current.Request.IsAuthenticated)

  - if (Model.IsHostedBy(HttpContext.Current.User.Identity.Name))

    %p You are the host for this event!

  - else if (Model.IsUserRegistered(HttpContext.Current.User.Identity.Name))

    %p You are registered for this event!

- else

  %strong RSVP for this event:

      

Code Sample 38. Multi-Level Condition Output - NHaml

Example of Loop - foreach

- foreach (var dinner in Model)

  %li

    !=Html.ActionLink(dinner.Title, "Details", new { id=dinner.DinnerID })

 

Code Sample 39. Loop ForEach - NHaml

Example of Global Html Encoding Setting in Web.Config

<nhaml autoRecompile="true" templateCompiler="CSharp4" encodeHtml="true" useTabs="true"

    indentSize="4">

 

Code Sample 40. Global HtmlEncoding Setting  - NHaml

Example of Html Encoding Inline

&= dinner.Address + " " + dinner.Country

 

Code Sample 41. Html Encoding Inline - NHaml

Global Master Page Support

NHaml has the concept of a site-wide master page (or layout) named Application.haml. In the layout, the view’s contents have a special placeholder ‘_’.

!!!

%html

       %head

              _ TitleContent

              _ HeadArea

       %body

                             _

Code Sample 42. Global Master Page - NHaml

Special Partial View Syntax

In NHaml, partial views use a ‘_’ as the first character in their file names. This allows you to place the contents of a partial view in another view (or layout) by using the special syntax of _ <viewname>.

              _ LoginStatus

 

Code Sample 43. Special Syntax for Partial Views - NHaml

Visual Studio Integration

Like Spark, NHaml is a third party view engine started by one person, so the Visual Studio tooling isn’t as good as the default view engine, though a few addins have been created by the community. Dave Newman created a syntax highlighting add-in for Visual Studio 2008: http://github.com/snappycode/hamleditor

There is also an Intellisense project for NHaml created by sztupy and available at: http://github.com/sztupy/nhamlsense for Visual Studio 2008.

Getting Support

Although NHaml has been around for a little longer than Spark, it isn’t quite as well documented (less reference material and less samples). 

A pretty good language reference can be found on the project’s site at: http://code.google.com/p/nhaml/wiki/NHamlLanguageReference

NHaml also has a Google Group where you can get answers to your questions: http://groups.google.com/group/nhaml-users

As with Spark (don’t forget it is Open Source), you can look at the code and attempt to figure out how things work on your own without using any documentation or support.

Strengths

·         Terse syntax that creates views with less code

·         Has a lot of features that help create html

·         Views don’t use the Page Class and so are easier to test

·         Supports languages other than C# and Visual Basic

Weaknesses

·         The syntax results in a greater learning curve

·         Poorly documented with hard to find samples

·         Error messages make it difficult to decipher syntax errors

 

Razor

Razor is a new view engine still under development at Microsoft. The initial pre-release of the view engine became available with the MVC 3 Preview 1 release. 

The Razor view engine is being designed to mix the code and markup together—not in the same sense as Spark (there aren’t any elements to represent functionality), but in the sense that the code and markup play well together with minimal control characters. Unlike the WebFormViewEngine, Razor doesn’t extend the System.Web.Page class.

The file extension currently used for views, partial views and layouts (master pages) is .cshtml and also in the future .vbhtml for VisualBasic support.

Below is a screenshot of a view written using the Razor view engine.

image

Screenshot 4.  NerdDinners Dinner/Index View in Razor

History

No history known about this one.

Key Features

Razor currently supports 14 features (plus more coming soon) from the desired feature list.

Feature

Notes

Multi Line Code Blocks

 

Inline Expression

 

Local Functions

Not as of MVC 3 Preview 1, but special HtmlHelper syntax coming soon.

Local Variables

 

Conditional Output

 

Support for Multiple Level Conditionals

 

Loops

 

Global Setting for Html Encoding

No setting currently , it is just on by default

Import Namespaces

 

Global Namespace Imports

 

Single View Master Page

 

Global Master Page

 

Content Placeholders

 

Support for Editor Templates

 

Visual Studio Integration

IntelliSense coming soon

Getting Started

In order to use the Razor view engine, you will need the ASP.NET MVC 3 Preview 1 framework installed.  You can download it here: http://www.microsoft.com/downloads/details.aspx?displaylang=en&FamilyID=cb42f741-8fb1-4f43-a5fa-812096f8d1e8#filelist

Check the release notes at that same link for any system requirements. 

Once you have ASP.NET MVC 3 Preview 1 installed, you will have a new project type for ASP.NET MVC 3 Web Application (Razor).

Dependencies

Currently the Razor view engine is in the System.Web.Mvc.dll and shipped with the MVC 3 Preview 1 framework, so there are no external dependencies if you have already downloaded it as mentioned in the Getting Started section above.

Feature Syntax

The syntax shown for Razor features is all subject to change, since it is based on a pre-release version.

Example of Multi Line Code Blocks

@{

       string message = "The time is: {0}";

       string timeString = DateTime.Now.ToShortTimeString();

       string output = string.Format(message, timeString);

}

 

The result from serverside code is: @output

 

Code Sample 44.  Multi Line Code Block - Razor

Example of Inline Expression

<script src="@Url.Content("~/Scripts/MSAjaxHistoryBundle.js")"

    type="text/javascript"></script>

 

Code Sample 45.  Inline Expression - Razor

Example of Creating and Using a Local Variable

@{

   string message = "Hello World";

}

 

The result message is: @message

 

Code Sample 46.  Local Variable Usage - Razor

Example of Conditional Output

<strong>Who's Coming:</strong>

@if (Model.RSVPs.Count == 0) {

    <text>No one has registered.</text>

}

 

Code Sample 47.  Conditional Output - Razor

Example of Multi Level Condition Output

@if (Request.IsAuthenticated) {

  if (Model.IsHostedBy(Context.User.Identity.Name)) {

     <p>You are the host for this event!</p>

  } else if (Model.IsUserRegistered(Context.User.Identity.Name)) {

     <p>You are registered for this event!</p>

  }

}

else

{

    <strong>RSVP for this event:</strong>

}

 

Code Sample 48.  Mult-Level Conditional Output - Razor

Example of Loop - Foreach

@foreach (var dinner in Model) {

  <li>

    @Html.ActionLink(dinner.Title, "Details", new { id=dinner.DinnerID })

  </li>   

}

 

Code Sample 49.  Loop - Foreach - Razor

Example of Global Namespace Import (Same as WebFormsViewEngine)

<pages>

   <namespaces>

      <add namespace="System.Web.Mvc" />

      <add namespace="System.Web.Mvc.Ajax" />

 

Code Sample 50.  Global Namespace Import - Razor

Example of Importing a Namespace in a View

@using NerdDinner.Helpers;

 

Code Sample 51.  Single View Namespace Import - Razor

Global Master Page Support

Razor has the concept of a site wide master page (or layout) like Spark and NHaml.  This allows you to create a master page in the Views/Shared directory named Application.spark and you don’t have to specify the layout page in the individual views.

Example of Setting a Master Page (Layout) in a View

@{

       LayoutPage = "~/Views/Shared/_Layout.cshtml";

}

 

Code Sample 52.  Single View Master Page - Razor

Example of Master Page with Content Placeholders

<head>

       <title>@View.Title</title>

       @RenderSection("HeadArea", optional:true)

</head>

 

Code Sample 53.  Master Page with Content Placeholders - Razor

Example of View with Multiple Content Elements

@{

       View.Title = "Upcoming Nerd Dinners";

       LayoutPage = "~/Views/Shared/_Layout.cshtml";

}

 

@section HeadArea {

       @Html.Partial("_Head", false)

}

 

This text will be in the view's main content … notice this is not in a section.

 

Code Sample 54.  View with Multiple Content Elements/Sections - Razor

Visual Studio Integration

Since the Razor view engine is being developed by Microsoft, you will (eventually) get full Visual Studio support.  With the ASP.NET MVC 3, Preview 1 release, some tooling has been added – though IntelliSense is not yet working.

New Project Template for Razor

There are now two choices for ASP.NET MVC 3 Web Applications – one for the ASPX (WebFormsViewEngine) and the other for Razor.

image

 

Add View Dialog

The add View Dialog box, now allows you to choose which view engine you are using – and Razor is now a choice for you.

image

 

Getting Support

Since MVC 3 Preview 1 is a pre-release version, it isn’t a fully supported release – though you can get community (and often team) support in the forums at: http://forums.asp.net/1146.aspx

Strengths

·         Easy to learn

·         Views are cleaner than WebFormViewEngine view syntax

·         Views don’t use the Page Class – so they are easier to test

Weaknesses

·         Not yet released – current documentation is minimal with no central location to find information on the view engine.

·         Error messages are hard to decipher when you get the syntax wrong

 

Summary

To conclude this Developer Review, I hope we have provided you with enough useful information about the default ASP.NET MVC view engine, Spark, NHaml and Razor to help you decide which is best for you.

Side Note

My Thoughts After Converting the Views NerdDinner’s Views

After converting the views of the NerdDinner example to Spark, NHaml and Razor here are my thoughts on the different view engines:

Default ASP.NET MVC View Engine
Still my favorite view engine, though the tendency of ending up with views that feel messy does bother me.  For client work, I will be using this view engine probably for quite some time – especially if the client  is going to be supporting the resulting views.

Spark
Initially the syntax reminded me of the year I  used ColdFusion, but once I got past that I really enjoyed the clean look the view has when it is complete.  I am really impressed with the functionality it provides  as well as the documentation and samples available for it.

NHaml
At first I wasn’t a fan of the Haml syntax, but its efficiency eventually attracted me to it. I can see using this view engine on my own site in the future, though I don’t think it is a good choice for working on a typical client’s site (if the client will be supporting it).

Razor
Though this view engine isn’t yet completed, the syntax that Razor uses is really easy to pick up and does leave the view looking better than on the default view engine. 

About the Author

Jason Haley has been working with Microsoft technologies for the past 15 years in various settings – mostly in the New England and Seattle areas.  Last year (2009), he decided to become an independent consultant and started Jason Haley Consulting.  Now almost a year of being gainfully unemployed, he is building his client base in the New England area and enjoying the opportunities of working with multiple clients instead of just a single full-time employer.  Jason also has a few open source projects on CodePlex, of which the most popular is PowerCommands for Reflector (http://powercommands.codeplex.com/)

Tags:

Follow the Discussion

Remove this comment

Remove this thread

close

Comments Closed

Comments have been closed since this content was published more than 30 days ago, but if you'd like to continue the conversation, please create a new thread in our Forums,
or Contact Us and let us know.