The search for a better View Engine – ASP.NET MVC

I have been evaluating the different view engines available for ASP.NET MVC.  In my last two posts I evaluated Brail and finally dismissed it since it didn’t match up to what I was looking for.

Just to recap – I’m looking for a view engine that will allow a web designer to create the views on my behalf, or at the very least work closely with the developers in terms of styling and layout.  The default ASP.NET view engine is simply not sufficient in this regard – the design was always aimed at developers, not designers.  On a higher level, projects like MVC Contrib are making this problem even worse.  Don’t get me wrong – I like MVC Contrib.  I’m simply making the point that while we are making development easier for developers, we are making it harder for designers to work with developers.

If you don’t believe me, go ask a designer to style this table.

<%= Html.Grid(Model.People).Columns(column => {
             column.For(x => x.Id).Named("Person ID");
             column.For(x => x.Name);
             column.For(x => x.DateOfBirth).Format("{0:d}");
         })
        .Attributes(style => "width:100%")
         .Empty("There are no people.")
         .RowStart(row => "<tr foo='bar'>") %>

I had a quick look at the different view engines available to see if any of them could help us in the right direction.

NHaml

NHaml is part of MVC Contrib and uses Haml syntax from Ruby.

#foo
    - foreach (var product in ViewData)
        - if (product.Category.CategoryName != null)
            %h2=product.Category.CategoryName
            - break
    %ul.productlist
        - foreach (var product in ViewData)
            %li
                = Html.Image("/Content/Images/" + product.ProductID + ".jpg", product.ProductName)
                .productdetail
                    =Html.ActionLink(product.ProductName, "Detail", new { ID=product.ProductID })
                    %br
                    Price:
                    =String.Format("{0:C2}", product.UnitPrice)
                        %span.editlink
                            (
                            =Html.ActionLink("Edit", "Edit", new { ID=product.ProductID })
                            )

Thanks to Scott Hanselman for the snippet.  Clearly this is not what I’m looking for.

Spark

I mentioned on Twitter that I’m evaluating different view engines and someone immediately recommended Spark to me.  I actually remembered that Phil Haack blogged about it so I was quite optimistic.

<viewdata products="IEnumerable[[Product]]"/>
<ul if="products.Any()">
  <li each="var p in products">${p.Name}</li>
</ul>
<else>
  <p>No products available</p>
</else

The syntax is certainly different and very html friendly (the Spark motto is “Html friendly – Less is more”).  However it’s still not what I’m looking for – while a designer would find the syntax reasonably familiar, I’m convinced that mixing html with evaluated code in this manner is not helping our cause in this regard.

NVelocity

My initial impression of NVelocity was very positive.  There seems to be very little information available for this view engine, but a couple of the examples looked very promising.  Here is what a foreach loop looks like.

#foreach( $recipe in $viewdata )
    <li><a href="Edit/$recipe.ID">$recipe.Name</a></li>
#end

Which is very much what I’m looking for.  However, take a look at the following snippet.

$HtmlHelper.LabelFor('elementid', 'Name:', "%{class='required', accessKey='N'}")

And we’re back to square one.  Or even worse:

#foreach($person in $people)
#beforeall
       <table>
               <tr>
               <th>Name</th>
               <th>Age</th>
               </tr>
#before
       <tr
#odd
       Style='color:gray'>
#even
       Style='color:white'>
#each
       <td>$person.Name</td>
       <td>$person.Age</td>
#after
       </tr>
#between
       <tr><td colspan='2'>$person.bio</td></tr>
#afterall
       </table>
#nodata
       Sorry No Person Found
#end

Finally, an answer

I completely understand why most view engines have complex syntax – we are trying to duplicate the functionality from the default ASP.NET view engine.  A developer isn’t going to use a view engine if it can’t do everything the built-in one can do, right?  Well, not necessarily…

A colleague introduced me to Smarty, a view engine designed to allow developers and designers to work together.  Here is a foreach loop in Smarty.

<ul>
{foreach from=$myArray item=foo}
    <li>{$foo}</li>
{/foreach}
</ul>

I was immediately impressed by the syntax.  Presentation logic is clearly separated from the actual html and it’s painfully obvious what is evaluated code and what’s not.  There are even modifiers to allow a designer to specify that a variable must be displayed in upper- or lowercase or to specify the datetime format.  I had a look at most of the functions and became convinced that this is exactly what I’m looking for.

There’s only one major problem – it’s a php view engine.

Writing my own view engine

I wanted to experiment and see if I could write a view engine (for ASP.NET) that uses the same syntax.  I found it surprisingly simple in some areas and surprisingly difficult in others.  It took me about an hour to be able to render a foreach statement (and another hour to be able to render nested foreach statements).  The tricky part is in structuring the code and allowing different kinds of functions (at the moment you should be able to add your own functions as well).

So this is where I am at the moment – I first want to try and structure the code a little better and at least implement all the functions that Smarty supports by default.  More on this will follow.

On a personal note

I usually don’t mention personal details in my blog, but I’m going to make an exception here.  I won’t be doing any blogging for at least 2 weeks since I’m off to London and Europe during which time I’m going to watch the Belgian Grand Prix. 

Happy coding.

02bel67