I have been working on a ASP.NET MVC application recently. This is my first real ASP.NET MVC application, previously I have only played with it. The transition from MonoRail is overall very smooth as they are so very similar, the only thing that I found painful was the WebForms view engine which feels clunky.

I like the MonoRail Brail engine because it allows for expressions in ${} syntax which severely decreases the usage of ugly <% %> tags that sometimes can make your templates hard to read. I was strongly considering using the ported Brail engine that exists in the MvcContrib project until I read Scott Hanselman's post about a view engine called Spark.

Simple example:

<ul>
  <li each='var product in products'>
    ${product.Name}
    <div class="product-detail" if="product.HasDetail">
      ///...
    </div>
  </li>  
</ul>

This is the view engine I have been looking for! I quickly downloaded the latest release, referenced the spark assembly from my MVC application and was testing it in a matter of minutes. After reading though the documentation I was able to convert all my WebForms views into spark views in just an hour (so far very small application with not many views).

This is how one WebForm view looked like:

<% foreach (var rev in ViewData["changesets"] as IEnumerable<Changeset>) { %>
  <div class="log-entry">
    <div class="log-entry-header">
      <a href="asd" class="rev-nr"><%= rev.Revision %></a>
      &nbsp;by&nbsp;
      <span class="rev-author"><%= rev.Author %></span>&nbsp;
      <span class="rev-date"><%= rev.Time %></span>&nbsp;
    </div>
    
    <div class="rev-message">
      <%= rev.Message %>
    </div>
    
    <ul class="rev-items">    <% 
      foreach (var item in rev.ChangeItems.Where(x => x.IsRelevant).Take(5)) { %>
      <li>
        <a href="asd"><%= item.Path %></a>
        <%     
        switch (item.Action)
        {
          case ChangeAction.Added:
            Response.Write("<em>added</em>");
            break;
          case ChangeAction.Deleted:
            Response.Write("<em>added</em>");
            break;
          case ChangeAction.Replaced:
            Response.Write("<em>replaced</em>");
            break;
          case ChangeAction.Modified:
        %>    
        (+<%=item.Diff.PlusLines%>, -<%=item.Diff.MinusLines%>)
        <%= Html.RouteLink("diff", "Diff", new { 
		reposName=rev.Repository.Name, 
		path=item.Path, 
		r1=item.Diff.FromRevision, 
		r2=item.Diff.ToRevision }) %>
        <%
          break;
        }
        %>
      </li>                            
      } %>                
    </ul>    
    <% if (rev.ChangeItems.Count > 5) { %>        
    <div class="rev-items-more">
      ... <%= rev.ChangeItems.Count %> more files in <a href="asd">changeset</a>
    </div>
    <% } %>
  </div>        
<% } %>    

This is not a very nice view, if I had kept WebForms I would have rewitten this, extracted some stuff to a helper method and maybe written a UserControl. But instead I rewrote it in Spark:

<div each="var set in changesets" class="log-entry">
  <div class="log-entry-header">
    <a href="asd" class="rev-nr">${set.Revision}</a>&nbsp;by&nbsp;                
    <span class="rev-author">${set.Author}</span>&nbsp;
    <span class="rev-date">${set.Time}</span>&nbsp;
  </div>
    
  <div class="rev-message">
    ${set.Message}
  </div>
    
  <ul class="rev-items">
    <li each="var item in set.ChangeItems.Where(x => x.IsRelevant).Take(5)">
      <a href="asd">${item.Path}</a>
      <em if="item.Action == ChangeAction.Added">added</em> 
      <em if="item.Action == ChangeAction.Deleted">deleted</em> 
      <em if="item.Action == ChangeAction.Replaced">replaced</em> 
      <if condition="item.Action == ChangeAction.Modified">
        (+${item.Diff.PlusLines}, -${item.Diff.MinusLines})                    
        ${Html.RouteLink("diff", "Diff", new { 
            reposName=set.Repository.Name, 
            path=item.Path, 
            r1=item.Diff.FromRevision, 
            r2=item.Diff.ToRevision })}
      </if>
    </li>
            
    <div class="rev-items-more" if="set.ChangeItems.Count > 5">
      ... ${set.ChangeItems.Count} more files in <a href="asd">changeset</a>
    </div>                
  </ul>                  
</div>

I find this a lot easier to read and understand than the html/<% %>/C# tag soup that is sometimes hard to avoid with WebForms. I also think a view engine like this make more sense, because Spark is a view engine tailor made for only one thing, to generate html!

So if this is your cup of tea when it comes to view engines, try it out.

6 comments:

loudej said...

That's a great example - thanks for posting this. I love the use of Linq on the ChangeItems collection.

--
Lou

Martin said...

Sweet! I'll try this out ASAP!

One additional thing I really hate about aspx-tags, or rather the VS IDE, is how everything gets reformatted every time and end-} is typed. Haven't found a way to turn that off...yet...

Anonymous said...

Great post!

I would like to use spark with my ASP.NET MVC application. Could you do a post and walk through how to get spark to work with an ASP.NET MVC app?

Thanks!

Torkel Ödegaard said...

I try to do a more detailed post about it.

Anonymous said...

Who knows where to download XRumer 5.0 Palladium?
Help, please. All recommend this program to effectively advertise on the Internet, this is the best program!

Anonymous said...
This comment has been removed by a blog administrator.