Canvas gets a Spark

Today I updated the CodeBetter.Canvas project to target the latest releases of NHibernate (2.1), FluentNhibernate (1.0 ) and Nhiberate Linq (1.0).

More importantly is the switch away from the MVC WebForms View Engine to the Spark View Engine. I’ve been learning and using Spark for the last month or so, and I’m a pretty big fan. I do think that you should strongly consider it for your next ASP.NET MVC project, it increases the readability and maintainability of your views, while being very easy to learn.

I think Spark is one of those love-it-or-hate-it kinda things, but I do think there are things anyone can learn from it. I would hate for ASP.NET developers to think that the default MVC view engine is the best (or even only) way to do things. Its good that Microsoft made the view engine pluggable, its great that developers might see new ways to mix layout and code.

I do worry that CodeBetter.Canvas is a little overwhelming from a learning point of view. If you’ve been doing .NET development the traditional way, then you’ll have a lot of new technologies and patterns to learn (MVC, Spark, DI, Unit Testing, Mocking, jQuery and O/R Mapping). I do worry about this, but I can’t imagine NOT adding a worthwhile feature like Spark for the benefit of those lacking the ambition and interest in improving their skill set. Some developers will suck it up and learn what they can, others will continue to fall behind – so be it.

As always, you can grab the source from Google Code

I do suggest that you check out the SparkViewEngine website for a great guide on setting it up and using it. You may also want to grab the latest source and use it instead of the 1.0 release (which is what Canvas is using) for the added caching capabilities which are excellent. However, I would like to show some Spark samples from Canvas to give you a quick idea of what it offers.

The first thing to take note of is that <%=XXX %> are gone, replaced with ${XXX}. I do find that this simple change does increase the readability a little, but the real advantage is that ${} will automatically HTML encode values thanks to the SetAutomaticEncoding setting of Spark set in the global.asax. If you don’t want encoding, you use !{XXX} instead (you’ll notice that Canvas uses both as needed).

You can pretty much look at Views/Shared/Application.spark to get a good feeling for what Spark is all about. This is the default master page layout used by all spark views (which can be changed or overwritten at multiple levels). First, you’ll notice that we are declaring a variable, errors for use later on (more on this in a bit). You should also notice that we are defining a global variable, Title – which individual views can set to control the page’s title (look a bit further down and you’ll see that the Title variable is being outputted within our head’s title tags).

Things get a lot more interesting with the <use> tags, which are equivalent to ContentPlaceHolders. Not only are they much more concise, but anything outside of an explicit content tag is automatically placed in the "view" placeholder. This helps reduce our code’s nesting and the ASPX soup-tag. Given a simple master page of:

<body>
   <use content="menu" />
   <use content="view" />
</body>

Our view can simply be:

<content name="menu">
  ....STUFF...
</content>
<p>The main content doesn't have to be nested in a content element</p>
<p>Yay! it's a small but useful feature</p>

Next you might notice the <LoginLogoutMenuItem> and <PageData> elements. This is Spark’s way to render a partial. Spark will look for a file named _LoginLogoutMenuItem.spark and _PageData.spark (in the shared folder, and in the controller’s view folder) and render it out. What I like most about these is the ease with which we can pass information to our partial: simply add attribtes to the tag, such as (this is how the errors variable defined at the top of the layout is being used):

<SomePartial heading="'This Is A String Value'" products="Model.Products" />

Although there’s a lot more to Spark, the last, and possibly coolest, feature is Spark’s ability to embedded attributes within html elements and attributes. For example, one way to write an IF/ELSE is to use Spark’s If/Else elements.

<if condition="Model == null">
  <h3>No Results were Found</h3>
</if>
<else>
    <table>
      ...do stuff
    </table>
</else>

Another approach is to use the attributes on existing elements(which s much nicer with just an if):

<h3 if="Model == null">No Results were found</h3>
<table if="Model != null">...</table>

Even more impressive the embedding of the each attribute. Take a look at the old PageError partial versus the new one:

<%@ Control Language="C#" AutoEventWireup="False" Inherits="CodeBetter.Canvas.Web.ApplicationViewUserControl<string[]>" %>
<ul id="pageErrors">
    <% Model.Each(e => { %>
        <li><%=e %></li>
    <% }); %>
</ul>

versus

<ul id="pageErrors">
    <li each="var d in data">${d}</li>
</ul> 

The same can be done at the attribute level, from the Spark documentation, take a look at how cleanly styles (or any other attribute) can be controlled:

<li each="var product in Products" class="first?{productIsFirst} last?{productIsLast}">
    ${H(product.Name)}
</li>

(as a bonus, the xxxIsFirst and xxxIsLast are automagically created by Spark when it sees the each attribute).

So, I hope that gets you interested in Canvas and in the Spark View Engine. There’s a lot more to both free projects than what you see here. Canvas covers a broad range of technologies and patterns. Spark offers caching (and donut-caching), javascript integration, macros, batch compilation and more.

This entry was posted in Uncategorized. Bookmark the permalink. Follow any comments here with the RSS feed for this post.

17 Responses to Canvas gets a Spark

  1. explorer2309 says:

    Disclaimer : This comment is not related to spark engine blog, but I could not find any other place to say this.

    I came across CodeBetterCanvas project this morning. I am quite excited to find a piece of very well structured code which can be used for developing real application with built in good practices. This should be very useful for a learner like me who is trying to follow good developers and learn from them.

    My request is – can the project add few other general capabilities like:
    1) Sorting the grid
    2) Searching user records
    Adding these capabilities can make the canvas more useful.

    Thanks for your good work!

  2. Issues:

    Controller:
    ————–
    1. You are creating unnecessary hierarchy of Controllers for some helper methods and security checking/redirecting. Instead, create extension methods of controller for those helper methods and use Authorize Attribute. It is obviously a design smell for a simple login/Registration there are three level deep inheritance hierarchy.
    2. Your controller is leaking all over the places, for example, in ModelBinder.cs you are using to add error messages, which can be also done with an extension method of ViewData. Moreover, the most offending one is your View is referring the Controller (_LoginLogoutMenuItem.spark) to get the Current User which breaks the MVC pattern very badly. On a side note, it seems your having an issue of maintain the Current User, I think a ViewModel base class with an ActionFilter can solve this issue pretty much.
    ModelBinder:
    —————–
    3. I don’t see any value where there are one ModelBinder per ViewModel and with this it seems there should a binder for each ViewModel, also the model binder you have provided does not take any benefit from the ASP.NET MVC framework, I mean auto populating object from the expression, validation etc, instead you are doing it by manual way which makes it even more dumber.
    4. I think the whole purpose of it is having some automation in both client/server validation, I think xVal is currently serving the purpose pretty well. Also they way you are handling the server side validation is a bit unusual, instead of copying the errors in ModelState directly, you are first putting it ViewData with a magic string, then copying it in ModelState at some point, not sure why this extra steps is required.
    5. For building the Json object you are doing it manually which plain wrong way of doing it. If you do not want to use any Built-in MS provided Json Serializer, fair enough, use some well known open source library like Json.net. There is no special character handling which breaks the json objects very badly e.g.
    Tip(“Please enter your :\”\name. 2-30 character”)
    6. I am not sure what are the advantages of validation js file over the popular jquery.validate.js and it has lot more features comparing to yours, if you want to automate with server use this instead of writing your own.

    There other issues as well, overall I do not find any value with the current state of Canvas. I will check again if you address the above issues.

  3. The canvas project is incredibly helpful for someone like myself that is just starting out. I’ve been learning about integrating ASP.NET MVC (or in this case, Spark) with the Nstack. Best practices on how to tie all the technologies together seems really scattered, and I’m just picking up bits and pieces along the way, so this project should help to bring it all together. Are there other sample projects you would recommend that demonstrate best practices of using ALT.NET technologies?

  4. The canvas project is incredibly helpful for someone like myself that is just starting out. I’ve been learning about integrating ASP.NET MVC (or in this case, Spark) with the Nstack. Best practices on how to tie all the technologies together seems really scattered, and I’m just picking up bits and pieces along the way, so this project should help to bring it all together. Are there other sample projects you would recommend that demonstrate best practices of using ALT.NET technologies?

  5. Eric says:

    Great article. I’m definitely going to give Spark a try based on your glowing recommendation. I’ve been doing the < % %> tags now for about 10+ years and Spark just seems a LOT cleaner and easier to read. I hadn’t seen any information on the partials before in Spark, so that is very cool to learn!

  6. karl says:

    Intellisense support isn’t great and it isn’t horrible. Try it out, maybe it’ll give you what you need.

  7. corey coogan says:

    I’ve been interested in Spark for a while as well, but something eluded to by the first post from Travis was intellisense. Although I love the cleanliness of of the Spark views, nesting everything in quotes means I have to type out everything exactly, like my old days developing ASP Classic in HomeSite.

    Is there any way around this for someone like me who forgets all the properties and extension methods available from my ViewModel?

  8. karl says:

    @Argos:
    Thanks, got it in now.

  9. Argos says:

    Hi Karl, first of all thanks a lot for setting this up.

    I noticed that the References folder is missing a dll: NHibernate.ByteCode.Castle.dll

  10. karl says:

    @Luke:
    That is pretty ironic. I’m glad the application is helpful to you.

    Kenny:
    I used NVelocity back when I was working with MonoRail – not sure if its changed much, I prefer spark. I didn’t even know about NDjango, so I’ll check it out.

  11. Kenny says:

    Did you consider any other view-engine? Like NVelocity or NDjango?

  12. Luke Foust says:

    It is quite a coincidence that you published this today since I was just converting your canvas project to spark last night (partly as a way to learn spark and part to better understand the structure of your code). I also just swapped out the authentication with OpenID and I must say that working with your code has been quite a pleasure. This is my first real exposure to NHibernate and Ninject (I usually use Structure Map). Keep up the great work.

  13. karl says:

    @Travis:
    No. There’s info on getting intellisense working in VS.NET at:
    http://sparkviewengine.com/usage/intellisense

    You basically disable R#’s intellisense in .spark files and let the native VS.NET take over (again only for those files). Even then though, I find the intellisense average at best. It isn’t a big feature I look for, but I can understand how it might be for some.

  14. Travis says:

    Does R# work in the views when editing them in VS.NET?