Found My Spark — The Spark View Engine

Found My Spark — The Spark View Engine

The super customisable ASP.NET MVC framework gives us the choice when it comes to many things. View engine being just one of them. Having used the default Web Forms view engine on personal projects, the NVelocity view engine at work, I was exposed to the Spark view engine whilst watching Tekpub — Mastering ASP.NET MVC 2 , Episode 6 — View Engines by Rob Conery.

I fancied a bit of a play and a practical comparison with the Web Forms view engine I know and…..maybe not love. I wanted to compare the way I write code and conditionals in my view. I was keen to see what alternative there was to the obtrusive Web Forms gator tags. I’m already happy with NVelocity, but as an open-minded, pragmatic programmer, I felt obliged and compelled to explore Spark’s offering — especially as Rob Conery recommended I do so.

For in depth information, including documentation and library downloads, check the Spark View Engine web site.Setting up the Scenario

My first action, as in most cases, was to set up a brand spanking new ASP.NET MVC 2 web application. In this instance, I just called it the SparkViewEngineSampler. After doing which, I had a moment of contemplation and decided I would base this example on a Formula 1 race results page having just witnessed a dramatic Turkish Grand Prix (thank you Mr Vettel).

Whilst having my fun with Spark, I wanted to make sure I knew exactly how it handled view models. So before creating my view, I invented the F1Result class which would give my view selected data from today’s race. Here is that very class:

namespace SparkViewEngineSampler.Models

{

public class F1Result

{

public DateTime Date { get; set; }

public string Location { get; set; }

public string LapRecordHolder { get; set; }

public Dictionary<string, string> Result { get; set; }

public string FastestLap { get; set; }

public F1Result()

{

Date = new DateTime(2010, 05, 30);

Location = “Istanbul, Turkey”;

LapRecordHolder = “1:24.770 — JP Montoya (2005)”;

Result = new Dictionary<string, string>

{

{“Lewis Hamilton”, “88.47.620” },

{“Lewis Hamilton”, “2.60” },

{“Mark Webber”, “24.20” },

{“Michael Schumacher”, “31.10” },

{“Nico Rosberg”, “32.20” },

{“Robert Kubica”, “32.80” },

{“Felipe Massa”, “36.60” },

{“Fernando Alonso”, “46.50” },

{“Adrian Sutil”, “49.00” },

{“Kamui Kobayashi”, “65.60” },

};

FastestLap = “V Petrov Renault 1:29.165”;

}

}

}

As you can see, I populated the properties in the constructor for ease of use in this sample. I try to make a point of not cluttering the controller, even on a sample project like this. I live by the tenet of the “skinny controller”.

With the data, and subsequently the view model, taken care of, I just had the job of passing them to my index view in the home controller. I decided to use this page for brevity. Just for conclusiveness, here is that code:

[HandleError]

public class HomeController : Controller

{

public ActionResult Index()

{

F1Result f1 = new F1Result();

return View(f1);

}

public ActionResult About()

{

return View();

}

}

That was that in terms of setting up the infrastructure. From now on, I’ll be focusing on aspects pertaining directly to the views and view engines.The Web Forms View Engine

The default view engine, the much-maligned-for-its-gator-tags view-engine, is the Web Forms view engine. To use this facility to present the results of today’s race I did the following:

  1. Amend the Home/Index.aspx page so that it inherited the generic ViewPage base class using F1Result as the type. In essence setting the view model to type F1Result.

  2. To allow for intellisense with the model, the SparkViewEnginSampler.Models namespace was then imported into the page using the @Import declaration

  3. I then added the code/tags to the view to get it display the model data how I wanted. The mark up looks like so:

<%@ Import Namespace=”SparkViewEngineSampler.Models” %>

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

<asp:Content ID=”Content1” ContentPlaceHolderID=”TitleContent” runat=”server”>

<%: String.Format(“{0} — F1 Grand Prix Result”, Model.Location) %>

asp:Content>

<asp:Content ID=”Content2” ContentPlaceHolderID=”MainContent” runat=”server”>

<%: String.Format(“{0} — F1 Grand Prix Result”, Model.Location) %>h2>

Race Detailsh3>

Date:

<%:Model.Date %>span>


Fastest Lap:

<%:Model.FastestLap %>span>


Lap Record Holder:

<%:Model.LapRecordHolder %>span>


div>

Resultsh3>

<%for (int i = 0; i < Model.Result.Count; i++)

{ %>

<%if (i % 2 == 0)

{ %>

style=”background-color: Green; color: White;”

<% } %>”>

<for each=”var racer in Model.Result”>

<if condition=”racerIndex % 2 == 0”>

if>

else>

Positionth> Driverth> Race Timeth>

tr>

thead>

<%: i + 1%>td> <%: Model.Result.Keys.ElementAt(i) %>td> <%: Model.Result.Values.ElementAt(i) %>td>

tr>

<% } %>

table>

:Content>

Observing this mark up extract, you can see I’ve accessed properties of the model, used a bit of C# code, a loop and conditional logic. When testing out a new view engine, I deliberately wanted to compare the use of these features.

Talking through the above view code wouldn’t teach us much. Redoing it using the Spark view engine and comparing features, well — as Rob Conery would say “exciting!”.

Here’s a quick peak at what the view looks like. Hmmmm, where is Sebastian Vettel’s name?

Now Using Spark……Configuring Spark

To enable this scenario to be recreated using the Spark view engine, the first step I took was to download the package from here. With that sitting nicely on my hard drive, I unzipped it and added a reference to Spark.dll and **Spark.Web.Mvc.dll **in my mvc application.

The second stage of the configuration process was to add to some setup code in global.asax to be run at startup. There is an alternative way to do this, declaratively, by specifying the settings in web.config. It seemed easier to use global.asax, but that doesn’t mean it is the best way. Taken directly from the spark documentation page, here is their setup coded added to my global.asax file:

protected void Application_Start()

{

var settings = new SparkSettings()

.SetDebug(true)

.AddAssembly(“SparkViewEngineSampler.Models.F1Result”)

.AddNamespace(“System”)

.AddNamespace(“System.Collections.Generic”)

.AddNamespace(“System.Linq”)

.AddNamespace(“System.Web.Mvc”);

ViewEngines.Engines.Add(new SparkViewFactory(settings));

}Recreating the View from the Top DownThe Master

I decided a good way to evaluate Spark by recreating the view would be to work from the top down, literally. So starting with the master page, Site.Master, to make it Spark compliant I had to rename it with .spark file extension. Easy enough. Straight after doing that I stripped out all the ASP.Net declarations and content placeholders to leave only pure html. And, here is that very markup — site.spark, formerly site.master:

DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Strict//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd”>

title> <link href=”../../Content/Site.css” rel=”stylesheet” type=”text/css” /> head>

F1 Resultsh1<>

div>

    ul>

    div>

    div>

    The first fix I made was to add the facility to name portions of the template where pages using this layout/master can inject their own content. Observe…..

    DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Strict//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd”>

    <use content=”TitleContent” />title> <link href=”../../Content/Site.css” rel=”stylesheet” type=”text/css” /> head>

    F1 Resultsh1>

    div>

      ul>

      div>

      div>

      div>

      div>

      div>

      body>

      html>

      If you can’t see what’s changed, that is probably a compliment to how unobtrusive spark is. If you did spot the change you will have noticed:

      Let’s remind ourselves of the Web Forms view engine alternative:

      <asp:ContentPlaceHolder ID=”MainContent” runat=”server” />Index.aspx (The View)

      Next step was to give the Index view the Spark treatment. I kicked this off by simply giving the page the .spark extension.

      Specifying the Layout and Model Type

      My first proper challenge was to change this:

      <%@ Import Namespace=”SparkViewEngineSampler.Models” %>

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

      into the appropriate Spark mark-up that would tell my page which layout to use and the type of model to use.

      It turns out there are a number of way to specify the master page. If you are keen to see them all, check out the Spark documentation. However, I think the easiest way is to rename site.spark, to application.spark and leave it in the Views/Shared folder. So this is what I did in this instance.

      Cool. Now how do I tell the page what type of model it will use? Remember, it has to be of type F1Result.

      Well, it transpired to be quite an easy process and involves no gator tags (these obtrusive suckers: ). Here’s what I did:

      Nice!Adding Section of Content to Placeholder Regions

      With the regions of Title and MainContent defined in the now Application.spark. How was I going to put my ‘stuff’ in them? First lets check the Web Forms code I had in place:

      <asp:Content ID=”Content1” ContentPlaceHolderID=”TitleContent” runat=”server”>

      <%: String.Format(“{0} — F1 Grand Prix Result”, Model.Location) %>

      asp:Content>

      <asp:Content ID=”Content2” ContentPlaceHolderID=”MainContent” runat=”server”>

      <%: String.Format(“{0} — F1 Grand Prix Result”, Model.Location) %>h2>

      Race Detailsh3>


      A lot of extraneous content not shown here


      asp:Content>

      And now here’s what I changed it to:

      <%: String.Format(“{0} — F1 Grand Prix Result”, Model.Location) %>

      content>

      <%: String.Format(“{0} — F1 Grand Prix Result”, Model.Location) %>h2>

      Race Detailsh3>


      A lot of extraneous content not shown here


      ontent>

      As with specifying placeholder regions, when using the Spark view engine, the mark-up for content regions is only a marginal improvement in terms of aesthetics.Writing Code in the View

      To access properties of the model and use other programming bits and bobs, the Index.aspx page had the following bits:

      <%: String.Format(“{0} — F1 Grand Prix Result”, Model.Location) %>

      <%: String.Format(“{0} — F1 Grand Prix Result”, Model.Location) %>

      <%:Model.Date.ToShortDateString() %>

      <%:Model.FastestLap %>

      <%:Model.LapRecordHolder %>

      <%: Model.Result.Keys.ElementAt(i) %>

      <%: Model.Result.Values.ElementAt(i) %>

      Observing this, even passively, those ‘gator’ tags really do grab your attention. Attention that some people don’t like being grabbed in such an obtrusive, irritating way. I believe this to be one of the rationales for the Spark view engines conception and most definitely a reason why a lot of people deferred to it. Love them or hate them, in this example of one-liners, they aren’t a serious problem. Although that bright yellow background is not particularly comforting to my eyes.

      So, what could Spark offer me as an unobtrusive alternative?

      Well, there are no gator tags or fluorescent yellow blobs everywhere (yay!). Here’s what you get for your money with Spark (a small snippet of the update mark-up):

      ${String.Format(“{0} — F1 Grand Prix Result”, Model.Location)}h2>

      Race Detailsh3>

      Date:

      ${Model.Date.ToShortDateString()}span>



      Fastest Lap:

      ${Model.FastestLap}span>



      Lap Record Holder:

      ${Model.LapRecordHolder}span>


      My first thoughts were that it is not so bad on the eyes. No discernible gator tags for sure. What I do think is that you have to do more leg (eye) work to locate the blocks of code. Whether you prefer this or not will probably determine whether Spark is for you or not. I’ve used NVelocity, and working without gator tags is not a problem for me.Loops

      To conclude my reconstruction using Spark, I needed to resolve my for loop. How wold it look without all those gator tags? In the Spark style of Html with “seamless” code, if they are going to deliver, surely this is their chance.

      Ok. Here’s the current code:

      <%for (int i = 0; i < Model.Result.Count; i++)

      { %>

      <%if (i % 2 == 0)

      { %>

      style=”background-color: Green; color: White;”

      <% } %>”>

<%: i + 1%>td> ${Model.Result.Keys.ElementAt(i)}td> ${Model.Result.Values.ElementAt(i)}td>

tr>

<% } %>

And, here’s what I produced using Spark:

${racerIndex + 1}td> ${racer.Key}td> ${racer.Value}td>

tr>

for>

tbody>

Why not dive right in and inspect exactly what I did?

First up, there is no for loop — what!? What we have is only a for each loop which is actually a tag with an ‘each’ element. Well, that’s nifty. But what if I need to keep track of the count/number of iterations? Then you use the name of the local (to the for each loop) variable with suffix index. See racerIndex in the mark-up above. This is the same for the count, e.g. racerCount. There’s a few more too. See the Spark Documentation for exhaustive information.

First block of code inside my for each loop is a conditional. Again, it is styled as tags, as (not valid) html tags.By now I, and hopefully you, realise they stick to their philosophy of ‘helping you to think in terms of html/mark-up when you are looking at such a page.

From then on it is just a case of accessing variables and writing out their values using ${} inline code syntax.

In this case, the only real difference between the code is that Web Forms has the obtrusive gator tags, while Spark replaces them with tags. For more complex scenarios, it may be easier to discern which view engine really is the best. But I’ve done my piece in reviewing the basics. I’ll leave you with the mak-up in full for both pages………Web Forms View Engine

<%@ Import Namespace=”SparkViewEngineSampler.Models” %>

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

<asp:Content ID=”Content1” ContentPlaceHolderID=”TitleContent” runat=”server”>

<%: String.Format(“{0} — F1 Grand Prix Result”, Model.Location) %>

asp:Content>

<asp:Content ID=”Content2” ContentPlaceHolderID=”MainContent” runat=”server”>

<%: String.Format(“{0} — F1 Grand Prix Result”, Model.Location) %>h2>

Race Detailsh3>

Date:

<%:Model.Date.ToShortDateString() %>span>



Fastest Lap:

<%:Model.FastestLap %>span>



Lap Record Holder:

<%:Model.LapRecordHolder %>span>


div>

Resultsh3>

<%for (int i = 0; i < Model.Result.Count; i++)

{ %>

<%if (i % 2 == 0)

{ %>

style=”background-color: Green; color: White;”

<% } %>”>

Positionth> Driverth> Race Timeth>

tr>

thead>

<%: i + 1%>td> <%: Model.Result.Keys.ElementAt(i) %>td> <%: Model.Result.Values.ElementAt(i) %>td>

tr>

<% } %>

tbody>

table>

div>

asp:Content>Spark View Engine

${String.Format(“{0} — F1 Grand Prix Result”, Model.Location)}

content>

${String.Format(“{0} — F1 Grand Prix Result”, Model.Location)}h2>

Race Detailsh3>

Date:

${Model.Date.ToShortDateString()}span>



Fastest Lap:

${Model.FastestLap}span>



Lap Record Holder:

${Model.LapRecordHolder}span>


div>

Resultsh3>

<for each=”var racer in Model.Result”>

<if condition=”racerIndex % 2 == 0”>

if>

else>

Positionth> Driverth> Race Timeth>

tr>

thead>

${racerIndex + 1}td> ${racer.Key}td> ${racer.Value}td>

tr>

for>

tbody>

table>

div>

content>