Adding a bit of Spark to Nerd Dinner

Right, here we go. Having talked about how to get Spark set up and a little about Spark usage, it’s time to put some rubber on the road and pedal to the metal etc

First we need to sort out that master page, converting it to a Spark master layout. Here’s the site.master:

 <%@ Master Language="C#" Inherits="System.Web.Mvc.ViewMasterPage" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" 
    "https://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="https://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
  <title>
    <asp:ContentPlaceHolder ID="TitleContent" runat="server" />
  </title>
  <link href="../../Content/Site.css" rel="stylesheet" type="text/css" />
  <meta content="Nerd, Dinner, Geek, Luncheon, Dweeb, Breakfast, Technology, Bar, Beer, Wonk"
    name="keywords" />
  <meta name="description" content="Host and promote your own Nerd Dinner free!" />
  <script src="/Scripts/jquery-1.3.2.js" type="text/javascript"></script>
</head>
<body>
  <div class="page">
    <div id="header">
      <div id="title">
        <h1>NerdDinner</h1>
      </div>
      <div id="logindisplay">
        <% Html.RenderPartial("LoginStatus"); %>
      </div>
      <div id="menucontainer">
        <ul id="menu">
          <li><%= Html.ActionLink("Find Dinner", "Index", "Home")%></li>
          <li><%= Html.ActionLink("Host Dinner", "Create", "Dinners")%></li>
          <li><%= Html.ActionLink("About", "About", "Home")%></li>
        </ul>
      </div>
    </div>
    <div id="main">
      <asp:ContentPlaceHolder ID="MainContent" runat="server" />
    </div>
  </div>
</body>
</html>

And the Spark master-layout equivalent:

 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
    "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="https://www.w3.org/1999/xhtml">
  <head>
    <global type='string' Title='"Title"'/>
    <title>${Title}</title>
    <link href="../../Content/Site.css" rel="stylesheet" type="text/css" />
    <meta content="Nerd, Dinner, Geek, Luncheon, Dweeb, Breakfast, Technology, Bar, Beer, Wonk"
        name="keywords" /> 
    <meta name="description" content="Host and promote your own Nerd Dinner free!" /> 
    <script src="/Scripts/jquery-1.3.2.js" type="text/javascript"></script>    
  </head>
  <body>
    <div class="page">
      <div id="header">
        <div id="title">
          <h1>NerdDinner</h1>
        </div>
        <div id="logindisplay">
          <LoginStatus />
        </div> 
        <div id="menucontainer">
          <ul id="menu">      
            <li>!{ Html.ActionLink("Find Dinner", "Index", "Home") }</li>
            <li>!{ Html.ActionLink("Host Dinner", "Create", "Dinners") }</li>
            <li>!{ Html.ActionLink("About", "About", "Home") }</li>   
          </ul>
        </div>
      </div>
      <div id="main">
        <use content="MainContent"/>
      </div>
    </div>
  </body>
</html>

Note the declaration and usage of the Title variable, the inclusion of a partial view template (LoginStatus) and the ContentPlaceHolder control equivalent (<use content=”” /> in div “main”).

Let’s look at the partial view vs the Spark partial file equivalent. Here’s the Web Forms version:

 <%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %>
<%
    if (Request.IsAuthenticated) {
%>
        Welcome <b><%= Html.Encode(Page.User.Identity.Name) %></b>!
        [ <%= Html.ActionLink("Log Off", "LogOff", "Account") %> ]
<%
    }
    else {
%> 
        [ <%= Html.ActionLink("Log On", "LogOn", "Account") %> ]
<%
    }
%>

and the Spark version:

 <if condition='Request.IsAuthenticated'>
  Welcome <b>${Context.User.Identity.Name}!</b>
  [ !{Html.ActionLink("Log Off", "LogOff", "Account")} ] (Spark)
</if>
<else>
[ !{Html.ActionLink("Log On", "LogOn", "Account")} ] (Spark)
</else>

I could probably make the Web Forms one a bit more compact but the point here is to draw comparisons between implementing the two approaches rather than try and weigh up the relative merits of each. I leave that as an exercise for the reader.

So, to actually render a page, lets look at the Home/Index view in both Web Forms and Spark versions. Web Forms:

 <%@ Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master"
   Inherits="System.Web.Mvc.ViewPage" %>

<asp:Content ID="Title" ContentPlaceHolderID="TitleContent" runat="server">
  Find a Dinner
</asp:Content>
<asp:Content ID="indexContent" ContentPlaceHolderID="MainContent" runat="server">
  <script src="https://dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=6.2" 
      type="text/javascript"></script>
  <script src="/Scripts/Map.js" type="text/javascript"></script>
  <h2>Find a Dinner</h2>
  <div id="mapDivLeft">
    <div id="searchBox">
      Enter your location:
      <%= Html.TextBox("Location") %>
      or
      <%= Html.ActionLink("View All Upcoming Dinners", "Index", "Dinners") %>.
      <input id="search" type="submit" value="Search" />
    </div>
    <div id="theMap"></div>
  </div>
  <div id="mapDivRight">
    <div id="dinnerList"></div>
  </div>
  <script type="text/javascript">

    $(document).ready(function () {
      LoadMap();
    });

    $("#search").click(function (evt) {
      var where = jQuery.trim($("#Location").val());
      if (where.length < 1)
        return;

      FindDinnersGivenLocation(where);
    });

  </script>
</asp:Content>

and the Spark version:

 <content name="MainContent">
  <set Title="'Find a Dinner (Spark)'" />
  <script src="https://dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=6.2" 
          type="text/javascript"></script>
  <script src="/Scripts/Map.js" type="text/javascript"></script>
  <h2>${Title}</h2>
  <div id="mapDivLeft">
    <div id="searchBox">
      Enter your location: 
      !{Html.TextBox("Location")} 
      or 
      !{Html.ActionLink("View All Upcoming Dinners", "Index", "Dinners")}.
      <input id="search" type="submit" value="Search" />
    </div>
    <div id="theMap"></div>
  </div>
  <div id="mapDivRight">
    <div id="dinnerList"></div>
  </div>
  <script type="text/javascript">

    $(document).ready(function() {
    LoadMap();
    });

    $("#search").click(function(evt) {
    var where = jQuery.trim($("#Location").val());
    if (where.length < 1) 
            return;

        FindDinnersGivenLocation(where);
    });

  </script>
</content>

Note the use of the <content> tag and the setting of the Title variable. Other than that the file is very similar to the Web Forms version. Of course we can compare how the two different versions render (the (Spark) notations in the Spark version were added intentionally to distinguish the two)

Nerdaspx Nerdspark

The other page I tackled was the Dinners/Index page as it uses the common pattern of iterating over a collection of objects for display. Here’s the Web Forms version:

 <%@ Page Inherits="System.Web.Mvc.ViewPage<NerdDinner.Helpers.PaginatedList<NerdDinner.Models.Dinner>>"
  Language="C#" MasterPageFile="~/Views/Shared/Site.Master" %>

<asp:Content ID="Title" ContentPlaceHolderID="TitleContent" runat="server">
  Upcoming Dinners
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
  <h2>Upcoming Dinners</h2>
  <ul>
    <% foreach (var dinner in Model)
       { %>
    <li>
      <%= Html.ActionLink(dinner.Title, "Details", new { id=dinner.DinnerID }) %>
      on
      <%= Html.Encode(dinner.EventDate.ToShortDateString())%>
      @
      <%= Html.Encode(dinner.EventDate.ToShortTimeString())%>
    </li>
    <% } %>
  </ul>
  <div class="pagination">
    <% if (Model.HasPreviousPage)
       { %>
    <%= Html.RouteLink("<<<", 
                               "UpcomingDinners", 
                               new { page=(Model.PageIndex-1) }) %>
    <% } %>
    <% if (Model.HasNextPage)
       { %>
    <%= Html.RouteLink(">>>", 
                               "UpcomingDinners", 
                               new { page = (Model.PageIndex + 1) })%>
    <% } %>
  </div>
</asp:Content>

And the Spark version:

 <content name="MainContent">
<viewdata model="NerdDinner.Helpers.PaginatedList[[NerdDinner.Models.Dinner]]" />
<set Title="'Upcoming Dinners (Spark)'" />
    <h2>${Title}</h2>
    <ul>
        <li each="var dinner in Model">     
            !{ Html.ActionLink(dinner.Title, "Details", new { id=dinner.DinnerID }) }
            on 
            !{ Html.Encode(dinner.EventDate.ToShortDateString()) }
            @
            !{ Html.Encode(dinner.EventDate.ToShortTimeString()) }
        </li>
    </ul>
    <div class="pagination">
        <if condition='Model.HasPreviousPage'>     
            !{ Html.RouteLink("<<<", 
                               "UpcomingDinners", 
                               new { page=(Model.PageIndex-1) }) }        
        </if>        
        <if condition='Model.HasNextPage'>       
            !{ Html.RouteLink(">>>", 
                               "UpcomingDinners", 
                               new { page = (Model.PageIndex + 1) }) }
        </if>
    </div>
</content>

Note the viewdata tag and the succinct syntax for generating the <li>s. Again we can play spot the difference.

NerdDaspx NerdDspark

Hopefully that’s give you at least a flavour of Spark itself and how easy it is to swap out the view engine in ASP.NET MVC. The Web Forms syntax is familiar to many of us but I must admit I’m impressed with the intuitive and succinct way in which Spark can represent my intent. I’d definitely like to spend more time with it exploring its capabilities.

I should close by saying I claim no particular expertise in Spark. There are almost certainly better ways of doing some of the things I’ve done. Please leave a comment if you think you can improve things. Thanks!