Developers Tessitura Community
  • Topical Tessitura Community Groups
  • More
Developers Tessitura Community
Community Docs Wiki The Secret Life of HTML Templates
  • Discussions
  • Community Docs Wiki
  • Events
  • Files
  • Members
  • Mentions
  • Tags
  • More
  • Cancel
  • New
Developers Tessitura Community requires membership for participation - click to join
  • +Community Developer Documentation
  • Browser-based custom screen auth token API authentication
  • Deploying network ticket printers via Windows Group Policy
  • +HTML Templates
  • +Impresario Database
  • List Filters in Custom Reports
  • New to Using Tessitura in a Software Developer Role? Start here!
  • SSRS Report Open Detail Window Links
  • The Secret Life of HTML Templates
  • +TNEW Customizations
  • Understanding Contributions endpoints in the REST Services

You are currently reviewing an older revision of this page.

  • History View current version

The Secret Life of HTML Templates

or: How I Learned to Stop Worrying and Just Write HTML Templates

or: HTML Templates: The Missing Manual

or: The HTML Templates documentation they don't want you to know about!

This article aims to explain the differences between the Razor template syntax used in Tessitura HTML Templates and the syntax that you might see used in training courses for Razor Pages in ASP.NET Core/MVC web applications. At present, the Tessitura documentation only scratches the surface of what is available syntactically, and doesn't really attempt to explain how HTML Templates are implemented.

The Big Secret

HTML Templates are rendered using an Apache-licensed, open-source project called RazorEngine, which is available on GitHub. To summarize the RazorEngine documentation, RazorEngine is a framework which consumes the Razor parser -- as is ASP.NET MVC. There is a difference between Razor's syntax and special features provided by these frameworks. RazorEngine only shares its syntax with other implementations like ASP.NET MVC. This is why convenience methods like @Html.Raw() (often seen in web results about Razor Pages) do not work in HTML templates -- the @Html helper is a class specifically implemented by the ASP.NET MVC framework. (RazorEngine instead has @Raw() built-in to provide the same functionality.) Reading the RazorEngine documentation can be informative. Tessitura appears to implement version 3.10 of RazorEngine.

The fundamentals of how Razor operates still apply. The Razor syntax parser converts a .cshtml template into a C# Execute() method on a generated class, which, when invoked, has access to the provided model and returns a string.

Assorted Syntactic Tips and Tricks

The version of C# available in Tessitura HTML Templates in Tessitura V15.1 is C# 5.0. In Tessitura V16, Razor templates will support C# 9.0, giving them support for interpolated strings (C# 6.0), local functions (C# 7.0), and other features.

The version of Razor available in Tessitura HTML Templates in V15.1 is "Razor 3", which is versioned as such because it shipped with ASP.NET MVC 3. This means technically, the syntax documentation linked in the Tessitura docs is WAY too new for what is actually in use. This explains why "templating methods" described in these docs are not functional in Tessitura HTML Templates.

Razor supports the use of a @functions directive, which gives you a space to define additional members (methods and properties) to be added to the generated class. Curiously, the HTML Templates editor does not syntax-color code inside of a @functions directive.

@functions {
private string SOME_URL_CONSTANT = "https://example.com";
private string LinkTag(string link) {
return "<a href=\"" + SOME_URL_CONSTANT + "\">" + link + "</a>";
}
}
@Raw(LinkTag("some text"))
@* Outputs:
<a href="https://example.com">some text</a>
*@

Methods are private because the template's execution is just another method in the same class.

The version of Razor used in RazorEngine 3.10 (Razor 3, shipped in ASP.NET MVC 3) also supports the @helper directive, which allows you to define a kind of function that contains markup, just like the rest of the template. This allows for easy reuse of template code. Helpers were removed in Razor 4, reappear in ASP.NET MVC 5, were removed again in ASP.NET Core, and finally code blocks were enhanced to allow for inline markup in functions, without the need for the @helper directive. Helpers can be used as "templating methods" which are otherwise unavailable as described above.

@helper BoldMe(string content) {
<b>@content</b>
}
@BoldMe("look at me, I'm bold!")
@* Outputs:
<b>look at me, I&#39;m bold!</b>
*@

The output of the helper correctly writes literal or encoded HTML like the rest of the template does.

A regular function can be made to behave like a templating method by defining it with a void type and then calling the imperative WriteLiteral() and Write() functions, which is basically what a Razor template compiles to in the first place. Then this function can be called inside a code block (@{}) to inject its output at that location.

@functions {
private void DIYRenderFunction(string content) {
WriteLiteral("<p>");
Write(content);
WriteLiteral("</p>");
}
}
@{ DIYRenderFunction("here are my paragraph tags & encoded content"); }
@* Outputs:
<p>here are my paragraph tags &amp; encoded content</p>
*@

Helpers can be passed into one another as arguments if your types are correct. The defined helper token refers to a method which returns a RazorEngine.Templating.TemplateWriter type, which is what writes template content as Literal or HTML-encoded inline. This type has a .ToString() method which can be used to cast to a string type at the point of use, but this is often non-optimal because if the helper template outputs HTML (which it often will), you will need to @Raw() the result when using it in another helper template. Luckily, C# supports the dynamic keyword in a type signature, which means you can pass in either a TemplateWriter or a raw string and RazorEngine will do the right thing at runtime:

@helper ItalicizeMe(dynamic content) {
<i>@content</i>
}
@helper BoldMe(dynamic content) {
<b>@content</b>
}
@ItalicizeMe(BoldMe("I'm bold, AND italic!"))
@ItalicizeMe("I'm only italic!")
@* Outputs:
<i> <b>I&#39;m bold, AND italic!</b>
</i>
<i>I&#39;m only italic!</i>
*@

You can also compose helpers by nesting them inside each other's templates, since helpers and @functions directives share the same scope (the generated class). In contrast, variables declared in a code block are local to the render method, so while they can be referenced in the template itself, they cannot be referenced in other class methods like helpers and functions.

A special syntax exists in Razor 3 for raw text. This is necessary when using helpers without surrounding tags. Information here: ASP.NET MVC 3: Razor’s @: and <text> syntax

Now, with all of these tools in our toolbox, only one question remains... Can we avoid writing inline styles?