Search code examples
c#asp.net-mvcrazorrazorengineemail-templates

Is there a way to make RazorEngine throw an exception rendering a template using JSON as the data model?


I am attempting to design an email templating system in ASP.NET using RazorEngine as my templating language. RazorEngine takes an email template (as a string or in a .cshtml file) and combines it with a data model to produce the output as a string. The data model can be provided in multiple formats.

For instance:

string template = "<h1>Hello @Model.name!</h1>";
var model = new { name = "world" };
var result = Engine.Razor.RunCompile(template, "templateKey", null, model);
// result = "<h1>Hello world!</h1>"

The RunCompile method will throw an exception if the template is expecting a value that is not provided by the data model, assuming the data model is provided as a C# object:

string template = "<h1>Hello @Model.name!</h1>";
var model = new {  };
var result = Engine.Razor.RunCompile(template, "templateKey", null, model);
// TemplateCompilationException

This is very useful behavior that I would like to have. However, for my purposes, the source of the data model must be JSON. This is easily accomplished by parsing the JSON into a C# object before providing it to RazorEngine:

String json = @"{ name: 'World' }";
var jsonModel = JsonConvert.DeserializeObject(json);
var result = Engine.Razor.RunCompile(template, "templateKey", null, jsonModel);
// result = "<h1>Hello world!</h1>"

, but the issue is that this process seems to destroy the type checking in the compilation process:

String json = @"{  }";
var jsonModel = JsonConvert.DeserializeObject(json);
var result = Engine.Razor.RunCompile(template, "templateKey", null, jsonModel);
// result = "<h1>Hello !</h1>"

Is there a way I can parse the JSON into a data model that will preserve the type checking and compile-time error for missing data expected by the template?


Solution

  • You can change your code to use ExpandoObjectConverter when deserializing object:

    var template = "<h1>Hello @Model.name!</h1>";
    var json = @"{ }";
    var converter = new Newtonsoft.Json.Converters.ExpandoObjectConverter();
    var model = JsonConvert.DeserializeObject<System.Dynamic.ExpandoObject>(json, converter);
    var result = Engine.Razor.RunCompile(template, "templateKey", null, model);
    

    Which throws an exception when the property doesn't exist, and returns expected result when the property exists.