Scott Hanselman

The Weekly Source Code 30 - Spark and NHaml - Crazy ASP.NET MVC ViewEngines

July 21, 2008 Comment on this post [20] Posted in ASP.NET | ASP.NET MVC | Source Code
Sponsored By

I've been getting more and more interested in how folks extend their applications using plugins and things. In my new ongoing quest to read source code to be a better developer, Dear Reader, I present to you thirtieth in a infinite number of posts of "The Weekly Source Code."

Spark

I'm really enjoying the extensibility points in ASP.NET MVC, but not as much as some people. Spark is a really promising ViewEngine from Louis DeJardin. You can download Spark here and join the mailing list here. Not only is it promising, it's also freaky. Freaky in that good, makes-you-think way.

Louis says "The idea is to allow the html to dominate the flow and the code to fit seamlessly." When he says HTML should dominate the flow, he's not kidding. Check this out:

<ul>
<li each='var p in ViewData.Model.Products'>
$p.Name; $Html.ActionLink[[ProductController]](c=>c.Edit(p.Id), "Edit");
</li>
</ul>

See the "each" attribute on the UL? Freakly. ;)

Remember this is NOT WebForms. That <li> and the each attribute are not controls, or parts of controls or runat=server or whatever. This is a complete ViewEngine. It's a templating language in and of itself. (As are most ViewEngines, although it's not an obvious point to a lot of folks getting started with ASP.NET MVC or any MVC Framework)

That means that Louis has complete control of what the syntax is, and as you can see, it's somewhere in between HTML and Something Else. He's still changing the syntax based on feedback, so this is your chance to get involved.

Here's Louis' Northwind "Listing By Category" page:

<viewdata 
model="IList[[Product]]"
CategoryName="string"/>

${PageTitle(CategoryName)}

<CategoryMenuItems category="ViewData.Model.Select(p=>p.Category).FirstOrDefault()"/>

<ul class="productlist">
<var styles='new[] {"odd", "even"}'/>
<li each="var product in ViewData.Model" class="${styles[productIndex%2]}">
<ProductImage style='"float:left;"'/>
<p>
<a href="/Products/Detail/${product.ProductID}">${product.ProductName}</a>
<br />
Price: ${String.Format("{0:C2}", product.UnitPrice)}
<span class="editlink">
(${Html.ActionLink[[ProductsController]](c=>c.Edit(product.ProductID), "Edit")})
</span>
</p>
<div style="clear:both;"></div>
</li>
</ul>

imageNotice  not only that the iterators live on the markup tags like <li> but also that you can create variables. See how an array called styles is created to hold the strings odd and even, then used to set the class on the <li> on the next line. The "jump into code block" is usually ${ } rather than <% %> which I find nice visually.

However, Spark is all about choice, so you can use EITHER ${ } or <% %>. Whatever makes you happy.

Also, check out the <CategoryMenuItems> tag. What's that? That's a partial view-file that gives you clean partial rendering.

If you have a partial view file that are starts with an underscore, then you can call that from a regular view using its name as a tag. You can see two partial view files in the screenshot at right. It's really just a really pretty syntactic sugar over include files. Neat though!

Go check out Spark and hear more at Louis' Blog.

NHaml

The deeply awesome Andrew Peters created NHaml (part of MVCContrib), an ASP.NET View Engine using the Haml syntax from Ruby. I've been showing Andrew's stuff as an extreme example of what a ViewEngine could look like.

For example, here's a standard "Listing by Category" page using the built-in WebForms ViewEngine, written using NHaml. Notice the lack of angle brackets. Notice that the UL tag never ends...it just leaves scope. The whitespace is significant. Haml users feel strongly about not repeating themselves, even in markup. They want "Markup Haiku."

#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 })
)

Other cool View Engines include Castle's Fork of NVelocity and Brail (in MVCContrib).

Related Links

Technorati Tags: ,,,

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Hosting By
Hosted in an Azure App Service
July 21, 2008 23:26
Spark looks really good to me, I don't like NHaml, reminds me a bit too much of Python.
July 21, 2008 23:30
You might want to mention that NHaml comes from the original Haml template engine, http://haml.hamptoncatlin.com/.
July 22, 2008 0:43
Is 'Braille' an intentional typo or an over-zealous spell checker?
July 22, 2008 0:45
Heh. Spell checker! Fixed.
July 22, 2008 1:27
Big fan of Haml already, so very excited to try NHaml. Spark looks like a little too much magic for my taste. Thanks for the writeup Scott! Always great to see how people are expanding and improving on open source Microsoft products!
July 22, 2008 2:37
my current employer's computer has microsoft word 2003. The program does not have center, justify, left margin, or right margin. What can be done about this? Your help is appreciated. Thank you
July 22, 2008 7:13
I love the idea of NHaml in ASP.NET MVC, but after trying it for awhile I went back to WebForms (gasp!) because I'm so addicted to Intellisense.
July 22, 2008 7:25
I love the power and ease of templating engines, over overly-bloated web controls; however trying to get a company to adopt such a practice is a challenge on its own. Thanks for the info on these template engines! I'm going to give them a spin.
July 22, 2008 8:24
Thanks much for writing about these. And what enthusiasm! :)

Like they say, "Nothing is impossible. Not if you can imagine it. That's what being a scientist developer is all about."

July 22, 2008 9:37
Starting to look like php soon.
July 22, 2008 10:14
Wow, very impressed by Spark, this is something that I have been looking for!

Working with ASP.NET MVC now and find the WebForms view engine very clunky and I was really wanting to switch to Brail (which I have used in the past with MonoRail), but Spark looks even better!

July 22, 2008 12:39
The markup of Spark reminds me of Coldfusion :-( I use NVelocity now, and I must say it's great that there are so many cool view engines. Although Visual Studio sometimes want to do weird indentation in NVelocity markup.

One thing I was wondering: what about performance? Webforms are compiled, even the markup is converted to response.Write and then compiled. If a view engine uses complicated syntax, is that parsed each time the page is requested? Or do view engine developers use compilation too? Perhaps you could write a post about that?

Thanks!
July 22, 2008 12:48
Spark looks more like the long lived Expression Language and custom tags which JSP people have used for ages now :P

I wrote a post about it for a while ago and it's interesting to see how people don't like it and custom tags. Can read the post and comments here.
July 22, 2008 13:37
The word 'extreme' may be unfairly pejorative. NHaml rocks IMO.
July 22, 2008 15:49
Haml is alright, but while in Rubyland I prefer Builder for my structured XML/XHTML needs, as dropping back into server side code is still fairly pleasant, and quite readable. However, the drawback of both these approaches is that its quite hard to reuse existing code that's not already in builder or haml - you've got to translate the raw html into the new language, so common layouts from other frameworks/fine websites will take more time to use. The benefit of these approaches is the same: you can't copy and paste existing code without thinking (at least a little) about what you're doing.
July 22, 2008 17:08
Hi Scott.
I've been trying to put together asp.net MVC, MVCContrib, Unity and NHalm but with no success. Have you or any or you, other reader, got this to work?

Best Regards, Bruno Figueiredo
July 22, 2008 18:46
just a quick note (I'm going to read the article although I've "met" NHaml before) without reading article, what is the point of view engines except the geekiness of the crowd (and uber-geekiness of Mr. Hanselman? ;-)

in the end you either buy a ready HTML template or pay money to get one that suits you, get one of millions for free, or you'll do it yourself with the help of _excellent_ CSS/XHTML editors like Microsoft Expression Web or Dreamweaver is...

and in the end productivity is 10 times better with this tools (in design and structure) than with any concise and short invented language that NHaml is...

it is a nic toy, but where is the real world? Can't really get it, the View is for designers, and you've got hundreds of them skilled in CSS/HTML and Photoshop PSD to XHTMLs conversion.

going to read if I find something new and sorry for rant;)
July 22, 2008 20:03
NHaml and Spark both result in a compiled class. A new instance of the existing class is used to render each request so performance or an interpreter overhead wouldn't be a concern. NHaml even supports pre-generating compiled view classes.

I like NVelocity very much as well. Aspects of Spark are obviously inspired by that view engine and others, NHaml included. The indentation of #if/#for/#component/#end, and of the code-braces-in-aspx, is one of the major motivations behind such a markup-centric template language.

July 22, 2008 21:07
eh, the only project I've seen use NVelocity is Cruise Control, which actually gets in the way of modifying CC.Net and takes away from easily extending CC.Net.

Also NVelocity has been dead since like 2003 unlike Java's Velocity, unless you count castle's fork of the project, which you can find here

I can see the use of Haml/NHaml cause it shortens the syntax of html (yay for the wrist friendly!), but usually most templating system causes an extra layer of parsing on top of a templating language(php/asp) without any valid reason to do so (smarty, nvelocity, expression engine, etc).
July 22, 2008 21:17
Thanks, I'll update the link to NVelocity. I always confuse those as it was forked.

Comments are closed.

Disclaimer: The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.