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>
Notice 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:
MVC,
ASP.NET,
NHaml,
Spark
Hosting By