Plinth Templating engine
$ dotnet add package Plinth.TemplatingHTML Templating library for generating emails and documents
Directory structure example for a template assembly:
Templates/
Email1.cshtml
Email2.cshtml
Email3.cshtml
Layouts/
DefaultEmail.cshtml
Shared/
ButtonLink.cshtml
Models/
EmailModel.cs
var engine = new TemplateEngineBuilder()
.AddTemplateAssembly(typeof(EmailModel).Assembly, new[] { "Layouts", "Shared", "Templates" })
.PrecompileInBackground() // optional
.Build();
:point_right: the paths given are optional. If none are given then you must specify the full path from the assembly root
Example, with no paths, specify "Templates/Email1"
with "Templates" specified, "Email1" will work as well
:point_right: This goes for references in your code to templates, as well as Layouts, Partials, and IncludeAsync's
:point_right: The root of the assembly is always included
:warning: NOTE! NOTE! NOTE! :point_right: Make sure your cshtml files are set to "Embedded Resource" in your .csproj
@using MyAssembly.Models // using directives work just like c#
@inherits Plinth.Templating.Template<EmailModel> // do this to enable Include functionality
@inherits Plinth.Templating.Template // if not using a model
@model EmailModel // set up your model
@{ Layout = "DefaultEmail"; } // optionally, set up a Layout
@{ await IncludeAsync("ButtonLink", Model.Link); } // example of including another template
<p>@Model.Title</p> // example of using the model
<p>@ViewBag.Subtitle</p> // example of using the view bag
@functions { // static functions
public static int Double(int x) => x * 2;
}
@{ // local functions (can access model and viewbag)
int Double() => Model.Number * 2;
}
// no model
var result = await engine.RenderAsync("Email1");
// with model
var emailModel = new EmailModel { ... }
var result = await engine.RenderAsync("Email1", emailModel);
// with viewbag
dynamic viewbag = new ExpandoObject();
viewbag.Field1 = 7;
var result = await engine.RenderWithViewBagAsync("Email1", viewbag);
// with model and viewbag
var emailModel = new EmailModel { ... }
dynamic viewbag = new ExpandoObject();
viewbag.Field1 = 7;
var result = await engine.RenderWithViewBagAsync("Email1", emailModel, viewbag);
You can render a string template and cache it for later use, or for one time use
:point_right: These following are cached by "TemplateKey1", and re-rendering with that same key will ignore the string template subsequent renders
// no model
var result = await engine.RenderRawAsync("TemplateKey1", "<div>Hello</div>");
// with model
var emailModel = new EmailModel { ... }
var result = await engine.RenderRawAsync("TemplateKey1",
"<div>@Model.Name</div>", emailModel);
// with viewbag
dynamic viewbag = new ExpandoObject();
viewbag.Field1 = 7;
var result = await engine.RenderRawWithViewBagAsync("TemplateKey1",
"<div>@ViewBag.Field1</div>", viewbag);
// with model and viewbag
var emailModel = new EmailModel { ... }
dynamic viewbag = new ExpandoObject();
viewbag.Field1 = 7;
var result = await engine.RenderRawWithViewBagAsync("TemplateKey1",
"<div>@Model.Name, @ViewBag.Field1</div>", emailModel, viewbag);
:point_right: The following are one-offs and will re-compile every time
// no model
var result = await engine.RenderRawOnceAsync("<div>Hello</div>");
// with model
var emailModel = new EmailModel { ... }
var result = await engine.RenderRawOnceAsync("<div>@Model.Name</div>", emailModel);
// with viewbag
dynamic viewbag = new ExpandoObject();
viewbag.Field1 = 7;
var result = await engine.RenderRawOnceWithViewBagAsync(
"<div>@ViewBag.Field1</div>", viewbag);
// with model and viewbag
var emailModel = new EmailModel { ... }
dynamic viewbag = new ExpandoObject();
viewbag.Field1 = 7;
var result = await engine.RenderRawOnceWithViewBagAsync(
"<div>@Model.Name, @ViewBag.Field1</div>", emailModel, viewbag);