Razor is a powerful templating language that enables developers to mix their C# knowledge to build dynamic outputs. Developers often conflate Razor with ASP.NET MVC. The two are separate technologies, although ASP.NET MVC does utilize Razor as its HTML rendering engine.

In this post, we’ll see how we can utilize the Razor engine to generate dynamic input without needing the ASP.NET MVC infrastructure. We’ll be using a .NET Standard 2 library, called RazorEngine.NetCore.

Use Cases for Razor Engine

So why might we want to use the Razor engine in our projects? Here are a few compelling use cases:

  • Emails
  • Bot / Chat Clients
  • Static Site Generators
  • eBook Publication

Razor can generate any string output and is not limited to HTML. Imagination is our only limiting factor when using the Razor engine.

Using the Razor Engine

The first step is to install the .NET package. This package uses .NET Standard 2, so it should work for .NET Core applications targeting the 2+ and 3+ runtimes.

dotnet add package RazorEngine.NetCore

In a console application, we can now create our first usage.

using System;
using RazorEngine;
using RazorEngine.Templating;

namespace Razoring
{
    class Program
    {
        static void Main(string[] args)
        {
            string template = "Hello @Model.Name!";
            var result = Engine
                .Razor
                .RunCompile(template,
                    "templateKey",
                    null,
                    new
                    {
                        Name = "World"
                    });

            Console.WriteLine(result);
        }
    }
}

After running the application, we get the following output.

Hello World!

The library caches all template compilations using the template key parameter. Our code can reuse the template using the Run command. Let us modify our application and see how that happens.

using System;
using RazorEngine;
using RazorEngine.Templating;

namespace Razoring
{
    class Program
    {
        static void Main(string[] args)
        {
            const string template = "Hello @Model.Name!";
            const string key = "templateKey";
            
            var one =
                Engine.Razor
                    .RunCompile(template,
                        key,
                        null,
                        new { Name = "World" });

            var two =
                Engine.Razor
                    .Run(key,
                        null,
                        new {Name = "Khalid"});

            Console.WriteLine(one);
            Console.WriteLine(two);
        }
    }
}

Note that the first call is to RunCompile, and the second call is to Run. The resulting output is unsurprising.

Hello World!
Hello Khalid!

So far, we’ve used anonymous objects against our template. Most developers utilize statically typed objects. Let’s modify our code one more time to take advantage of a newly created Person class.

using System;
using RazorEngine;
using RazorEngine.Templating;

namespace Razoring
{
    class Program
    {
        static void Main(string[] args)
        {
            const string template = "Hello @Model.Name!";
            const string key = "templateKey";
            
            var one =
                Engine.Razor
                    .RunCompile(template,
                        key,
                        typeof(Person),
                        new Person { Name = "World" });

            var two =
                Engine.Razor
                    .Run(key,
                        typeof(Person),
                        new Person { Name = "Khalid" });

            Console.WriteLine(one);
            Console.WriteLine(two);
        }
    }

    public class Person
    {
        public string Name { get; set; }
    }
}

Our results are exactly like the previous sample, but now we’re using our Person class to strongly-type our template.

Hello World!
Hello Khalid!

Notes For Razor Engine

There are few items to decisions to consider when using this library.

Static Vs. Instance

The library has a static engine accessible through Engine.Razor, but we can also create an instance of the Razor engine for use in our applications.

var config = new TemplateServiceConfiguration();
// .. configure the instance

var service = RazorEngineService.Create(config);

We can register this instance with a dependency injection framework and share it throughout our application.

Custom Helpers

The Razor engine does not have many of the features found in ASP.NET MVC. That means we can’t merely transplant our MVC views into a console application and hope it all works. To get any helpers, we have to recreate them.

public static class TextHelper
{
    public static string Decorate(string value)
    {
        return "-= " + value + " =-";
    }
}

ITemplateServiceConfiguration configuration = 
    new TemplateServiceConfiguration();

configuration.Namespaces.Add("Helpers");

IRazorEngineService service = 
    RazorEngineService.Create(configuration);

string template = 
    @"Hello @Model.Name, @TextHelper.Decorate(Model.Name)";

string result = 
    service
        .RunCompile(
            template,
            "templateKey", 
            null, 
            new { Name = "World" });

Debugging

Template creation can be tricky and fraught with syntax errors and runtime bugs. Luckily, this library has some great debugging features. Since Razor ultimately gets converted into functional C# code, we can step through our compiled templates. We can read more about debugging on the GitHub readme.

Conclusion

It’s vital to realize ASP.NET MVC uses Razor as a template engine, and that they aren’t the same thing. The good news is we can use Razor too for our bespoke needs. Using the library RazorEngine.NetCore, we can add powerful templating features to any .NET Core application. The library provides a relatively simple wrapper around Razor with tools like caching, template management, and caching. I hope you found this post helpful, and let me know how you’re using Razor Engine in your projects.