Avoiding the mess of <% } %> in ASP.NET MVC

If you read Hadis' post onĀ  ASP.NET MVCD you'll have noticed the rather unpleasant return to the bad old days of ASP code embedding in views. Even when we're following the MVC pattern closely you're still going to find a mess of C# syntax littering your beautifully crafted HTML. I don't there's much worse than having to open a script block just to finish a loop (the <% } %> alluded to in the title).

Fortunately the designers of the new MVC framework had the foresight to allow the use of different ViewEngines that allow HTML / code rendering in with far more pleasant syntax. Take, for example, Spark (my personal favourite). The entire ASP.NET rendering engine is ditched in Spark, and we're given a whole new syntax that melds control of rendering into your HTML seamlessly. Taking Hadis' original example of looping around a list we go from

   1:  <%foreach (Customer customer in ViewData.Model)
   2:  {%>
   3:      <tr>
   4:          <td style="width: 98px">
   5:              <%=Html.ActionLink(customer.Firstname, "Edit", new { id = customer.Id}) %>
   6:              &nbsp;
   7:          </td>
   8:          <td style="width: 112px">
   9:              <%=customer.Lastname %>
  10:              &nbsp;
  11:          </td>
  12:      </tr>
  13:  <% } %>

to

   1:  <for each="Customer customer in Customers">
   2:      <tr>
   3:          <td style="width: 98px">
   4:              ${Html.ActionLink(customer.Firstname, "Edit", new { id = customer.Id})}
   5:              &nbsp;
   6:          </td>
   7:          <td style="width: 112px">
   8:              ${customer.Lastname}
   9:              &nbsp;
  10:          </td>
  11:      </tr>    
  12:  </for>

There's a lot more to Spark than just this, conditional attributes on existing HTML elements (remember it goes through a whole different parser... they're doing some real magic under the hood), which enables statements like:

   1:  <p if='!user.IsLoggedIn()'>Login form</p>
   2:  <p elseif='user.HasRole(RoleType.Administrator)'>Hello - admin</p>
   3:  <p elseif='user.HasRole(RoleType.Registered)'>Hello - registered user</p>

or how about an each attribute on HTML elements so we don't need to use the <for/> element? Our updated HTML becomes:

   1:  <tr each="Customer customer in Customers">
   2:      <td style="width: 98px">
   3:          ${Html.ActionLink(customer.Firstname, "Edit", new { id = customer.Id})}
   4:          &nbsp;
   5:      </td>
   6:      <td style="width: 112px">
   7:          ${customer.Lastname}
   8:          &nbsp;
   9:      </td>
  10:  </tr>    

The one downside is that you'll lose the existing ASP.NET capabilities when it comes to master pages (they have their own version), user controls (they have something similar but not exactly the same) and built in ASP.NET controls. However, since we're coming at how we build our web applications from a different angle by using MVC, it's not necessarily a bad thing. It does mean that a lot of stuff that ASP.NET controls just did for us we need to relearn, however the state of Javascript extension packages has moved on considerably in the past few years (consider JQuery and their recent success in getting included in future release of ASP.NET).

If you're having a play with MVC give Spark a try, or one of the many other ViewEngines that are out there.

Comments

# re: Avoiding the mess of <% } %> in ASP.NET MVC
Gravatar Regarding this:

<p if='!user.IsLoggedIn()'>Login form</p>
2: <p elseif='user.HasRole(RoleType.Administrator)'>Hello - admin</p>
3: <p elseif='user.HasRole(RoleType.Registered)'>Hello - registered user</p>

I'm curious if you consider the logic of rendering contents based on the users' role, something that should be in the view? Irrelevant of the view engine of course...
Left by Hadi Hariri on 10/17/2008 11:11 AM
# re: Avoiding the mess of <% } %> in ASP.NET MVC
Gravatar I see what you mean, I think... I agree that the if shouldn't really have the elseif="user.HasRole(RoleType.Administrator)" call, but instead should be more elseif="user.IsAdministrator", with the controller being responsible for populating the user object with the appropriate data. However I can't see how we can avoid having if logic in the view without massive duplication of the views. Either that or the controller will have to start returning HTML in the view data (don't even go there).
Left by Daniel Gray on 10/17/2008 11:41 AM
# re: Avoiding the mess of <% } %> in ASP.NET MVC
Gravatar I have to agree, with both of you. ;-)
I would agree totally with what Hadi is saying if this were an MVP variant, passive view. I agree with Dan in that your view should only really be bound to your view data.
In the end, the view is responsible for presentation and things like what colour or string something should be are presentation concerns, not domain logic concerns.
Left by Tom Quinn on 10/17/2008 12:35 PM
# re: Avoiding the mess of <% } %> in ASP.NET MVC
Gravatar Glad you like it. :)

In the end the use user-role is really just to illustrate the switch-like syntax of if and elseif attributes. It could just as easily be showing inventory state like in-stock, back-ordered, out-of-production.
Left by Louis DeJardin on 12/3/2008 8:59 AM

Leave Your Comment

Title*
Name*
Email (never displayed)
 (will show your gravatar)
Url
Comment*

Please add 4 and 5 and type the answer here:

Preview Your Comment.