I have followed this tutorial to use the RazorEngine to generate HTML emails (without ASP.NET MVC). It worked fine when I used either a strongly typed view or an anonymous object as the model:
Layout.cshtml
@model dynamic
// html contents...
C# snippet
var template = Encoding.UTF8.GetString(Properties.Resources.ContractList);
var model = new
{
ContractList = list
};
var templateService = new TemplateService();
var html = templateService.Parse(template, model, null, null);
Then I gave it a cache name, as recommended on the third part of the tutorial:
templateService.Parse(template, model, null, nameof(Properties.Resources.ContractList));
It worked fine with the strongly typed object, but with the anonymous object I started receiving this message as of the second time it ran:
Invalid token for impersonation - it cannot be duplicated
How can I resolve this and still use an anonymous object for the model?
I have seen solutions (here, here) that suggest transforming the anonymous object to an ExpandoObject
, but I'd like to avoid that if possible.
After reading the RazorEngine docs, I found some examples on their upgrading page which showed how to use Engine.Razor
. The easiest way to do it is:
var html = Engine.Razor.RunCompile(
template,
nameof(Properties.Resources.ContractList),
null,
model
);
This solved the issue. Just beware that they don't recommend the above format, because internally it will call AddTemplate
every time, and that it will throw an exception when you use the same cache_name
for different templates. Instead they recommend precompiling on startup:
// Once at startup (not required when using an ITemplateManager which knows how to
// resolve cache_name)
Engine.Razor.AddTemplate(cache_name, razorTemplate)
// On startup
Engine.Razor.Compile(
cache_name,
typeof(MyModel) /* or model.GetType() or null for 'dynamic'*/
)
// instead of the Razor.Parse call
var result = Engine.Razor.Run(
cache_name,
typeof(MyModel), /* or model.GetType() or null for 'dynamic'*/
model
)