Razor outside of MVC
I had a project which involved generating fairly large XML documents and passing those documents onto a message bus. One option is to do it all in code: that is use the System.Xml.Linq set of classes to build up the appropriate structure. It works pretty well for small XML payloads, but I've found can get a bit unwieldy for larger documents.
That's when I looked at templating options. Razor came to mind pretty quickly for a few reasons. This is a work project, so anything that comes from Microsoft and has tooling is going to be an easier "sell". Razor is designed to output tag-based text - after all, it is a view engine for MVC to generate HTML.
But wait a second. As I just said, isn't Razor simply a view engine within ASP.NET MVC to generate HTML for browsers? Thankfully no. My project isn't a web project at all: it's a Windows Service, but no matter, the Razor engine can be used outside of MVC. So you get all the nice simplicity of Razor to generate my XML.
RazorEngine
Even better is that Matthew Abbott has a GitHub project which has done most of the hard work in wrapping the Razor engine in a simple library - downloadable with NuGet of course. As an example, let's run through using RazorEngine in a new console app.
Quick Sample
First things first, start a new Console application and add RazorEngine as a reference via NuGet. As an aside, if you're using Visual C# Express, NuGet will only install into the Web Developer edition. To workaround it, create the console project in Visual C# Express, then open it in Visual Web Developer and add the package via NuGet.
The template will use a very simple model class named TemplateModel:
namespace Sample {
public class TemplateModel {
public string Header { get; set; }
}
}
Next, add the Razor template file named template.cshtml:
@model Sample.TemplateModel
<?xml version="1.0" encoding="utf-8"?>
<sample>
<header>@Model.Header</header>
</sample>
Razor Intellisense
Now you may notice that you don't get intellisense in the cshtml file. The solution is to add a web.config file to the project which fixes the Visual Studio tooling: see this blog post for the details.
Lastly, in Program.cs we need to compile and run the template:
using (var razor = new TemplateService()) {
razor.Compile(File.ReadAllText("template.cshtml"), typeof(TemplateModel), "main");
var xmlOutput = razor.Run("main", new TemplateModel { Header = "Hello World!" });
Console.WriteLine(xmlOutput);
}
Console.ReadLine();
F5 and the console should print the xml with "Hello World!" between the header tags. Very simple:
Includes
One handy feature I've used is to split up the template and use the Include method. I believe RazorEngine supports layouts but I've not tried that yet.
Let's say that the content tag is defined is a new template, named child.cshtml:
@model Sample.BaseModel
<content>@Model.Info</content>
BaseModel looks as you'd expect:
namespace Sample {
public class BaseModel {
public string Info { get; set; }
}
}
Change TemplateModel so that it extends BaseModel:
public class TemplateModel : BaseModel {
As a quick aside, I could have added a property with a type of BaseModel to TemplateModel instead of inheritance. In fact it would probably be a better choice, for just for the sake of demonstration, let's go with inheritance just this once.
We need to include child.cshtml into template.cshtml like so:
<header>@Model.Header</header>
@Include("child", (Sample.BaseModel)Model)
Then the relevant section of Program.cs becomes:
razor.Compile(File.ReadAllText("child.cshtml"), typeof(BaseModel), "child");
razor.Compile(File.ReadAllText("template.cshtml"), typeof(TemplateModel), "main");
var xmlOutput = razor.Run("main", new TemplateModel { Header = "Hello World!", Info = "The content goes here." });
Console.WriteLine(xmlOutput);
Running this time we should see the extended, complete XML. I like it.


