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?
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.