Leveraging Razor Templates Outside of ASP.NET: They’re Not Just for HTML Anymore!
The Razor syntax is much more than just a clean way to write ASP.NET MVC Views and WebMatrix web pages. In fact, with a working knowledge of the Razor API, you can leverage Razor templates in any application. The Razor API exposes a powerful library for parsing, compiling, and executing templates created using the Razor syntax. This article will explore the Razor API and follow the lifetime of a Razor template from text to powerful templating solutions, including examples such as unit testing ASP.NET MVC views and creating a highly-maintainable email generator. The Razor Template Lifecycle Figure 1 shows the lifecycle of a Razor template.  Figure 1: The Razor template lifecycle.Templates based on the Razor syntax combine code and content in powerful ways. The Razor API translates these plain text templates to .NET source code - the same kind of source code that you and I write every day. Just as with the source code that we developers write, Razor API-generated code compiles into new .NET types just like any other: simply create and execute a new instance to produce a rendered result! Meet the Players Before jumping into exactly how the API works, here is a quick overview of the relatively small number of components involved in the process of transforming a plain text template into an executable Razor template class: - RazorEngineHost: Contains the metadata required for creating Razor Templating Engines. Things like the base class name, output class name (and namespace), as well as the assemblies and namespaces required to execute the generated template.
- RazorTemplateEngine: Using configuration data provided by a RazorEngineHost, the Template Engine accepts a stream of text and transforms this text into .NET code (represented by a CodeCompileUnit) that gets compiled into a .NET type.
- Custom Template Base Class: Though not technically part of the Razor API, the Razor Templating Engine requires a custom template base class to use as a base class for the generated template type.
- CodeDomProvider: Also not technically part of the Razor API, the CodeDomProvider class (from the System.CodeDom.Compiler namespace) compiles CodeCompileUnits into .NET Types, making them available for .NET applications to consume. The Razor Templating API offers two CodeDomProvider implementations to compile RazorTemplateEngine-generated CodeCompileUnits: The CSharpCodeProvider and VBCodeProvider. As their names indicate, these two implementations compile C#- and Visual Basic-based Razor templates respectively.
Compiling Templates with the Razor API Consider the Razor template which renders customer order information shown below. Customer ID: @Order.CustomerID Customer Name: @Order.CustomerName Order ID: @Order.ID
Items: Quantity Unit Price Product
@foreach(var item in @Order.LineItems) { @item.Quantity @item.Price @item.ProductName }
Tax: @Order.Tax Order Total: @Order.Total
As you’ll soon see, the Razor Templating API provides the ability to transform this template into a .NET class and execute it against a model, rendering the output shown below. Customer ID: HSIMPSON Customer Name: Homer Simpson Order ID: 1234
Items: Quantity Unit Price Product 1 $1.50 Jelly Doughnut 4 $0.75 Glazed Doughnut
Tax: $0.10 Order Total: $4.60
Obviously, the customer order information template includes nothing inherently web related, so why should rendering it depend on the ASP.NET runtime? Luckily, it doesn’t have to. In fact, the output displayed in the previous snippet is the result of a command line application using the code snippets from this article! Configuring the Razor Template Engine The RazorTemplateEngine class does most of the heavy lifting to transform Razor template text into usable .NET source code. Before creating a RazorTemplateEngine, however, the application must provide a set of properties that inform the engine about how to properly translate the Razor template text it receives. These properties come in the form of a RazorEngineHost. Creating a RazorEngineHost The code snippet below contains an example RazorEngineHost initialization. var language = new CSharpRazorCodeLanguage(); var host = new RazorEngineHost(language) { DefaultBaseClass = "OrderInfoTemplateBase", DefaultClassName = "OrderInfoTemplate", DefaultNamespace = "CompiledRazorTemplates", };
// Everyone needs the System namespace, right? host.NamespaceImports.Add("System");
To begin, the RazorEngineHost’s constructor accepts a RazorCodeLanguage specifying the target template’s code language. This example produces a host that can parse Razor templates written using C#. To support templates written in Visual Basic, supply a VBRazorCodeLanguage instance instead. The additional initializer properties instruct the code generator to emit code with a particular class name, deriving from a custom template base class, and residing in a particular namespace. Finally, add the System namespace to the list of imported namespaces required for the generated class to compile just as you would import a namespace in a normal, hand-written class. The custom template base class - in this example named OrderInfoTemplateBase - is somewhat special. Though it does not need to implement any “official” .NET interface, the base class does need to provide methods with the following signatures: - public abstract void Execute()Once populated with generated code, this method contains a series of calls to the Write methods to render the template contents.
- void Write(object value) and void WriteLiteral(object value)The RazorTemplateEngine populates the Execute() method with calls to the Write() and WriteLiteral() methods, much like using an HtmlTextWriter to render a Web Forms server control. While the Execute() method controls the flow of the template rendering, these two methods do the heavy lifting by converting objects and literal strings to rendered output.
This next code snippet contains the simplest possible implementation of a Razor template base class. public abstract class OrderInfoTemplateBase { public abstract void Execute();
public virtual void Write(object value) { /* TODO: Write value */ }
public virtual void WriteLiteral(object value) { /* TODO: Write literal */ } }
While this implementation will, of course, do nothing to render any content, it is the minimum code required to successfully compile and execute a template class. Later sections in this article will revisit and expand upon this class, making it much more useful. | & | | 
By: Jess Chadwick
Jess is independent software consultant. He has over eight years experience with .NET technologies ranging from embedded devices in start-ups to enterprise-scale Web farms at Fortune 500 corporations. He is a Microsoft MVP in ASP.NET, technical editor of Silverlight 3 Programmers Reference (Wrox) and is actively involved with the community, acting as leader of the NJDOTNET Central New Jersey .NET user group. Jess also tries his hardest to maintain an active blog, hosted at http://blog.jesschadwick.com.
jesschadwick@hotmail.com |