Click here to Skip to main content
Click here to Skip to main content

SharpTemplate - A strongly typed HTML templating solution for Script#

By , 15 Jan 2010
Rate this:
Please Sign up or sign in to vote.

Introduction

Script# is a free tool that enables developers to author C# source code and compile it to JavaScript. In doing so, it helps to fully leverage the productivity of .NET tools and the Visual Studio IDE. While Script# delivers on what it promises, one thing that it lacks though is HTML templating that can fully leverage its power. SharpTemplate is a templating engine meant to fill this gap. This article is meant to be a tutorial for using the SharpTemplate HTML templating engine.

Background

HTML templates are a necessity in this era of rich web application development. Traditionally, HTML template engines were written in JavaScript and made use of RegEx parsing and Eval to convert templates into HTML. While this works, the obvious disadvantages are low performance and debugging/maintenance difficulties. JavaScript generation tools like Script# have greatly offset the difficulty of developing huge sites using JavaScript, but they still leave the HTML templates to be managed by the traditional JavaScript based engines. This, to some extent, defeats the purpose of a static type checking tool like Script#. SharpTemplate aims to fill this gap by providing a compile time solution for HTML templating.

Prerequisite

You are expected to know about or have used Script# to some extent. Also, it would help if you can take a minute to visit the SharpTemplate site and go through its usage instructions.

To try out the sample application, you need to have Script# and SharpTemplate installed in your machine.

SharpTemplate tutorial

Generating Plain HTML

Plain HTML is the simplest to generate. A sample is shown below...

<%@ template name="RenderPlainHTML" args="" %>
<p>SharpTemplate has the below advantages...</p>
<ul>
    <li>Compile time type checking</li>
    <li>Leverages .Net tools and Visual Studio IDE</li>
    <li>Super efficient compared to client side template engines</li>
</ul>

Let us understand the above template code first. The @template tag indicates a template fragment. A SharpTemplate template file can contain multiple @template tags. Each @template tag would be converted into a static method in C#. The name attribute in the @template tag would be the name of the corresponding C# method. The args attribute would be the arguments to the corresponding C# method, none in this case.

The C# code generated by SharpTemplate for the above template is as below...

public static string RenderPlainHTML(ArrayList b)
{
    bool parentBuffer = (b != null);
    b = b ?? new ArrayList();
    b.Add(Script.Literal(@"'<p>SharpTemplate has the below advantages...<" + 
          @"/p><ul><li>Compile time type checking</li>" + 
          @"<li>Leverages .Net tools and Visual Studio IDE</li><li>" + 
          @"Super efficient compared to client side template engines</li></ul>'"));
    return parentBuffer ? "" : b.Join("");
}

The important point to note here is that even though the args attribute for the @template tag is empty, SharpTemplate has emitted an argument, namely ArrayList b. This argument is useful when nesting template calls (calling another template from within a template). As of now, we can ignore this and invoke the method with null as its first argument value. What is happening within the method is very obvious. The HTML string gets added to the array list (treated as a string buffer) and is joined together at the end.

Interleaving C# code with HTML

SharpTemplate has borrowed heavily from ASP.NET with respect to its syntax. To embed code amidst the HTML, you use the <% %> markup as shown below:

<%@ template name="IntersperseCode" args="int count" %>
<ui>
<%
    for(int i = 0; i < count; ++i)
    {
    %><li>Script# with SharpTemplate is a great combo!</li><%
    }
%>
</ui>

The template above takes a single argument, namely count, and repeats the message that number of times. SharpTemplate emits all text/code embedded within <% %> as it is (with appropriate indentation, if possible). The resulting C# code is shown below:

public static string IntersperseCode(ArrayList b, int count)
{
    bool parentBuffer = (b != null);
    b = b ?? new ArrayList();
    b.Add(Script.Literal(@"'<ui>'"));
    for(int i = 0; i < count; ++i)
    {
        b.Add(Script.Literal(@"'<li>Script# with SharpTemplate " + 
                             @"is a great combo!</li>'"));
    }
    b.Add(Script.Literal(@"'</ui>'"));
    return parentBuffer ? "" : b.Join("");
}

The important point to note is that the code embedded within the template can be any valid C#. It can access any of the standard APIs or your custom APIs. SharpTemplate doesn't do any interpretation of this code except for indentation inference.

Embedding C# expressions into HTML

Again, the expression syntax is borrowed from ASP.NET. To embed any string/numerical/boolean expression within the HTML, you enclose them within the <%= %> tag, as shown below.

<%@ template name="EmbedExpression" args="int count" %>
<ui>
<%
    for(int i = 1; i <= count; ++i)
    {
    %><li><%= i %> squared is <%= i * i %></li><%
    }
%>
</ui>

The generated C# code is self explanatory.

public static string EmbedExpression(ArrayList b, int count)
{
    bool parentBuffer = (b != null);
    b = b ?? new ArrayList();
    b.Add(Script.Literal(@"'<ui>'"));
    for(int i = 1; i <= count; ++i)
    {
        b.AddRange(new object[] {
            Script.Literal(@"'<li>'"),
            i,
            Script.Literal(@"' squared is '"),
            i * i,
            Script.Literal(@"'</li>'")
        });
    }
    b.Add(Script.Literal(@"'</ui>'"));
    return parentBuffer ? "" : b.Join("");
}

Having static helper methods/properties

At times, one may face the need to do some complex calculation or pre-computation that should be better kept outside of the template code itself. SharpTemplate allows emitting pure code to support such scenarios. A sample is shown below...

<%
  private static int _Cube(int i)
  {
    return i * i * i;
  }
%>

<%@ template name="EmbedExpression2" args="int count" %>
<ui>
<%
    for(int i = 1; i <= count; ++i)
    {
    %><li><%= i %> squared is <%= i * i %>, cube is <%= _Cube(i) %></li><%
    }
%>
</ui>

The first <% %> block that appears in the template file before any of the @template fragments would be treated as pure code, and would be emitted as it is. This block can be used to emit static methods and properties that may get used during the course of the template processing. Below is the C# code generated for the above template.

private static int _Cube(int i)
{
    return i * i * i;
}

public static string EmbedExpression2(ArrayList b, int count)
{
    bool parentBuffer = (b != null);
    b = b ?? new ArrayList();
    b.Add(Script.Literal(@"'<ui>'"));
    for(int i = 1; i <= count; ++i)
    {
        b.AddRange(new object[] {
            Script.Literal(@"'<li>'"),
            i,
            Script.Literal(@"' squared is '"),
            i * i,
            Script.Literal(@"', cube is '"),
            _Cube(i),
            Script.Literal(@"'</li>'")
        });
    }
    b.Add(Script.Literal(@"'</ui>'"));
    return parentBuffer ? "" : b.Join("");
}

Nested templates

In many scenarios, you may want to refactor some repeated templates into a template fragment of their own and call into them as required. The special argument ArrayList b comes into play here. To invoke a template from within another template, you just put in the code within the <% %> block and pass in b as the first parameter to the call.

<%@ template name="Render" args="" %>
<div>
    <% RenderPlainHTML(b); %>
</div>
<div>
    <% IntersperseCode(b, 3); %>
</div>
<div>
    <% EmbedExpression(b, 3); %>
</div>
<div>
    <% EmbedExpression2(b, 3); %>
</div>

The corresponding C# code is shown below:

public static string Render(ArrayList b)
{
    bool parentBuffer = (b != null);
    b = b ?? new ArrayList();
    b.Add(Script.Literal(@"'<div>'"));
    RenderPlainHTML(b);
    b.Add(Script.Literal(@"'</div><div>'"));
    IntersperseCode(b, 3);
    b.Add(Script.Literal(@"'</div><div>'"));
    EmbedExpression(b, 3);
    b.Add(Script.Literal(@"'</div><div>'"));
    EmbedExpression2(b, 3);
    b.Add(Script.Literal(@"'</div>'"));
    return parentBuffer ? "" : b.Join("");
}

The HTML generated by invoking Render(null) is shown below (indentation added for clarity)...

<div>
    <p>
        SharpTemplate has the below advantages...</p>
    <ul>
        <li>Compile time type checking</li>
        <li>Leverages .NET tools and Visual Studio IDE</li>
        <li>Super efficient compared to client side template engines</li>
    </ul>
</div>
<div>
    <ui>
      <li>Script# with SharpTemplate is a great combo!</li>
      <li>Script# with SharpTemplate is a great combo!</li>
      <li>Script# with SharpTemplate is a great combo!</li>
    </ui>
</div>
<div>
    <ui><li>1 squared is 1</li><li>2 squared is 4</li>
    <li>3 squared is 9</li></ui>
</div>
<div>
    <ui><li>1 squared is 1, cube is 1</li><li>2 squared is 4, 
       cube is 8</li><li>3 squared is 9, cube is 27</li></ui>
</div>

Other tidbits

To register a namespace that is being referenced within the template code, you can put in code similar to that shown below towards the beginning of the template file before any code/template blocks:

<%@ register namespace="System.XML" %>

To register an alias, you can put in code similar to that shown below towards the beginning of the template file before any code/template blocks:

<%@ register alias="SysScript = System.Script" %>

If for some reason you want to change the default namespace under which the C# template class is generated, you can use the code shown below (at the beginning of the template file):

<%@ set namespace="AnoterNamespace" %>

Points of interest

Using SharpTemplate instead of other client-side templating engines has hugely helped save cost and boost developer productivity.

History

  • 16th Jan 2010: Initial post.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

shivashankarp
Architect www.globalscholar.com
United States United States
I hold a bachelors degree in Computer Science & Engineering and am currently a Software Architect at GlobalScholar working on cutting edge technological solutions for education. Prior to this, I was at Microsoft working on Microsoft Outlook and Microsoft Office Live. My areas of technical specialization include Web/Ajax, Microsoft .Net, compilers and microprocessors. Other than work, I spend quite some time reading latest happenings in science/technology, hacking out some pet projects, playing musical instruments and being in yoga.

Comments and Discussions

 
QuestionNeed SharpTemplate for VS2010 PinmemberManiVannan M21-Feb-12 18:25 
QuestionAny particular version of Script# required? PinmemberJim Raden29-Jan-10 11:14 
AnswerRe: Any particular version of Script# required? PinmemberJim Raden29-Jan-10 11:23 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web02 | 2.8.140421.2 | Last Updated 16 Jan 2010
Article Copyright 2010 by shivashankarp
Everything else Copyright © CodeProject, 1999-2014
Terms of Use
Layout: fixed | fluid