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.

Creating the RazorTemplateEngine

Using the configuration provided in the previously-created RazorEngineHost, this next example shows how straightforward it is to instantiate and generate code with a RazorTemplateEngine.

// Create a new Razor Template Engine
    
RazorTemplateEngine engine =
   new RazorTemplateEngine(host);
    
// Generate code for the template
GeneratorResults razorResult =
   engine.GenerateCode([TextReader]);

The RazorTemplateEngine.GenerateCode() method accepts a TextReader to provide the Razor template text and produces generated code in the form of GeneratorResults. This result holds (among other things) a CodeCompileUnit representing the template’s generated source code.

To demonstrate, Listing 1 contains an example of what the GeneratorResults for the Customer Order Information template would look like represented as C# code.

Compiling a Razor Template

The final step in the process of converting Razor text into an executable .NET class is compiling the generated source code into a .NET assembly, as shown next.

CompilerResults compilerResults =
   new CSharpCodeProvider()
      .CompileAssemblyFromDom(
         new CompilerParameters(/*...*/),
         razorResult.GeneratedCode
      );

The CodeDomProvider.CompileAssemblyFromDom() method converts the CodeCompileUnit from the previous steps (razorResult.GeneratedCode) and outputs the compiled types in the form of CompilerResults. The CompilerResults object contains plenty of interesting data describing the compiled output, including a reference to the assembly with the newly-created template class type (in this example the template class type is named OrderInfoTemplate).

Executing a Razor Template

Configuring and compiling a Razor template produces a usable .NET type deriving from the base type specified in the RazorEngineHost properties. To process this template and render template output, simply create a new instance of the template type and execute it. Though there are several ways to create a new instance of a type, the Activator.CreateInstance(Type) function is the easiest (if perhaps not the most efficient) way.

Once you’ve created an instance of your custom Razor template type, simply call the .Execute() method to execute the generated code.

var template = (OrderInfoTemplateBase)
               Activator.CreateInstance(/*...*/);
template.Execute();

Congratulations, you have now leveraged the Razor API directly to manually create, compile, and execute your first Razor template class!

Advanced Templating Logic

Previously we discovered that, at a minimum, a valid Razor template base class must implement the Execute(), Write() and WriteLiteral() methods. However, these methods are merely a starting point. Like any other .NET base class, template base classes can expose additional properties or methods to the template classes derived from them. This is how template base classes provide data and functionality to templates that derive from them.

For example, take a look at the template containing numerous references to a variable named @Order shown in the original snippet at the beginning of this article. For this template to compile and execute properly, the custom base class specified in the RazorEngineHost.DefaultBaseClass property must expose a protected (or greater) access level “Order” property. Thus, to qualify as a base class for this template an Order property must be added to the OrderInfoTemplateBase class. The result of this change can be seen in this snippet.

public abstract class OrderInfoTemplateBase
{
    public CustomerOrder Order { get; set; }
    public abstract void Execute();

As this next snippet demonstrates, the application can now assign a CustomerOrder value to the template’s Order property prior to executing the template. With the Order property set, the template produces the rendered text originally featured.

var template = (OrderInfoTemplateBase)
               Activator.CreateInstance(/*...*/);
template.Order = CustomerOrders.GetOrder(1234);
template.Execute();

Putting the Razor Templating Engine to Work

Now that you understand the basics of creating and executing Razor templates outside of the ASP.NET framework, let’s take a look at a few common scenarios that might benefit from this new-found knowledge.

Unit Testing ASP.NET MVC or WebMatrix Views

The ASP.NET MVC 3 release introduces the Razor view engine, enabling developers to write ASP.NET MVC views using the Razor syntax. Though many best practices advocate keeping the logic in your views as limited and simple as possible, executing unit tests outside of the ASP.NET runtime against Razor-based MVC views can still be very beneficial.

Compiling an ASP.NET MVC Razor View without ASP.NET MVC

Take a look at the code snippet for an example of an ASP.NET MVC Razor view.

<p>
   Order ID:
   <span id='order-id'>@Model.OrderID</span>
</p>
<p>
      Customer:
      @(Html.ActionLink(
            @Model.CustomerName,
            "Details", "Customer",
            new { id = @Model.CustomerID },
            null))
</p>

The default ASP.NET MVC Razor view class exposes properties such as Model, Html, etc., that this view relies on. Thus, in order to compile and execute the view outside of the ASP.NET MVC runtime, you must create a custom template base class that implements these properties as well. This next example contains a snippet from the OrderInfoTemplateBase, modified to include the Model and Html properties so that it may be used to compile the previous view.

public abstract class OrderInfoTemplateBase
{
    public CustomerOrder Model { get; set; }
    public HtmlHelper Html { get; set; }

The OrderInfoTemplateBase class now fulfills the template’s dependencies on the ASP.NET MVC base classes, allowing the OrderInfoTemplateBase to act as a stand-in for the ASP.NET MVC base classes. Introducing custom base classes such as OrderInfoTemplateBase provides complete control over the properties and functionality provided to the template. Custom base classes also alleviate the need to execute ASP.NET MVC views within the ASP.NET MVC runtime. Listing 2 shows the power of swapping production components with mock objects. By replacing the production HtmlHelper class with a mock implementation, the unit test can easily make assertions against - and therefore confirm the validity of - code in the view without relying on the ASP.NET MVC runtime.

The ability to inject mock and stub objects to take the place of production types is a great boon for unit tests. Without this ability, most sites must resign to running all UI tests through slow and unreliable browser-based testing. In stark contrast, injecting mock and stub objects allows developers to create unit tests that execute in mere milliseconds.

Apply Razor Templates to Traditional Text Templating Scenarios

Generating template-based emails is just one more example in which Razor templates make perfect sense.

Many ASP.NET applications send email notifications. Although the .NET Framework provides an effective way to deliver emails, ASP.NET applications often need to generate the body of those emails using some sort of template. Third-party solutions can often make templating easier, however, instead of leveraging one of these solutions, many developers end up “rolling their own.” As with most do-it-yourself solutions, home-grown templating APIs often become difficult to maintain or their original creator moves on to their next opportunity leaving the next owner to scratch his/her head wondering how to maintain templates created using the proprietary techniques.

Basing templating solutions on a well-known and well documented syntax like Razor helps avoid this situation. Because Razor templates can output much more than just HTML, they are well suited to most templating tasks. To demonstrate, take a look at this next example which includes a sample email template written using Razor syntax:

Hello, @ServiceRequest.CustomerName!
    
Thank you for requesting more information about
@ServiceRequest.ServiceName on
@ServiceRequest.CreateDateDisplayValue.
Please find the information your requested below
and we look forward to hearing from you again!
    
@ServiceRequest.DetailedInformation
    
Sincerely,
@ServiceRequest.SenderInformation
    
[ Information current as of @DateTime.Now ]

Listing 3 contains the full Razor email template base class necessary to compile the template text.

Notice how the ServiceRequestEmailGeneratorBase class’s Write() methods populate a string buffer. After it’s done populating the buffer, the class then converts the buffered text into the body of a new MailMessage. This particular base class remains happily unaware of how its descendants call the Write methods. In fact, it knows nothing about the Razor Templating API at all!

Listing 4 shows the template in action in the form of an application that pulls customer service requests from a database and sends the customer a custom email generated from the Razor template.

This application retrieves template data from a database and executes an instance of the ServiceRequestEmailGeneratorBase template class against each set of data, producing the previously-discussed email message as a result. The application then sends the resulting email to the user via an SmtpClient.

Hello, Homer Simpson!
    
Thank you for requesting more information about
Donuts on 1/15/2011 11:04:12 AM.
Please find the information your requested below
and we look forward to hearing from you again!
    
  Donuts are delicious!
    
Sincerely,
Big Corp.
    
[ Information current as of 1/15/2011 11:04 AM ]

I have witnessed (and even developed) the email generation example many times, and each implementation seems drastically different than the next. Since this approach leverages standardized and well-documented components of the .NET Framework, the resulting solution becomes easy for any developer to understand and maintain.

Code Generators Generating Code Generators

Code generation is a powerful tool in any developer’s arsenal. Code generators help reduce repetitive typing (and thus human error) or even encourage a code standard across team members. Chances are you’ve been using code generation for quite some time, even if you weren’t aware of it. Ranging from generators built in to Visual Studio such as those which generate Windows Forms code-behind to the T4 templating engine and proprietary products, code generators make our lives much easier.

The last scenario we’ll explore shows an example of the Razor templating engine acting as yet one more option for code generation. Given an appropriate template written with the Razor syntax and a set of custom parameters, the Razor API can produce the same source code as any other code generator. This example shows how to use the same API functionality leveraged previously in this article to generate and even compile a C# class on the fly.

The API components required for C# code generation are no different than those used previously: a RazorEngineHost, a RazorTemplateEngine, and a custom template base class. The C# code generation base class shown in Listing 5 is almost exactly the same as the simple base class seen in previous examples, with only a few more simple properties added in order to specify the details for the generated C# class such as namespace, class name, etc.

Listing 6 contains the Razor template for the C# class we wish to generate. Notice the slightly more advanced logic which intelligently interprets the properties populated in the base class to do things such as generate using statements, and property and method declarations.

After compiling the Razor template, your application can execute the template against various sets of data to produce C# classes on the fly. Once generated, your application can manage these C# classes in many ways, such as saving the source code to disk or even passing it right back into the CSharpCodeProvider to compile and/or execute the C# code that the Razor template just generated. Listing 7 demonstrates the latter option, generating a C# class from a Razor template and immediately executing the generated code.

Take a moment to consider the power the ability to generate and execute code on the fly can provide. This ability makes many scenarios possible that simply aren’t possible using traditional static compilation and execution approaches.

Actually, this Might Be a Bad Idea…

Despite being an impressive demonstration of Razor’s power and flexibility, generating C# or Visual Basic code from Razor templates is, quite frankly, a bad idea. Razor’s ability to differentiate between code and content actually does more harm than good when producing output such as C# code. This confusion is quite understandable: how can the parser tell the difference between content and code when the content is code? Additionally, most scenarios requiring dynamic code generation and compilation would probably be better off leveraging one of the dynamic languages available via the Dynamic Language Runtime such as IronPython or IronRuby.

However unsuitable Razor templates might be for generating C# and Visual Basic code, this example proves that Razor templates can produce far more sophisticated output than simple HTML. Feel free to apply Razor templating to applications well beyond the scope of web development!

Conclusion

The Razor templating syntax is a very powerful solution to common template-based problems. Since its API is publicly exposed and very easy to use, Razor-based solutions don’t have to be restricted to the ASP.NET runtime. Properly configured, Razor templates can provide an effective and maintainable approach to solving a multitude of templating scenarios within any .NET environment.

What problems have you been facing that might be solved with Razor templates? Now you’ve got the tools to go fix them! Good luck and happy templating!