In my previous post, I’ve shown how to use the RazorEngine template engine in order to generate EmailMessages in an MVC-like pattern. However, when compared to real MVC, we have the ability to create more complex views, using utility classes/methods, such as @Html and @Url. In this article we’ll see how we can simulate that behavior, by using a custom Template base class. For this article, we’re going to show how to embed a CSS file into the template, thus allowing us to generate more user-friendly email.Let’s start with our code from the previous post, and see how we can improve it:
protected MailMessage GenerateMail<T>(T model, [CallerMemberName] string viewName = "")
{
string resultHtml = null;
string resultText = null;
var htmlTemplate = GetTemplate(viewName);
var textTemplate = GetTemplate(viewName, .txt);
var config = new TemplateServiceConfiguration();
using (var service = new TemplateService(config))
{
if (!string.IsNullOrWhiteSpace(htmlTemplate))
resultHtml = service.Parse(htmlTemplate, model, null, null);
if (!string.IsNullOrWhiteSpace(textTemplate))
resultText = service.Parse(textTemplate, model, null, null);
}
var mailMessage = new MailMessage
{
BodyEncoding = Encoding.UTF8
};
if (string.IsNullOrEmpty(resultText) && string.IsNullOrEmpty(resultHtml))
throw new InvalidOperationException("View was not found");
if (string.IsNullOrEmpty(resultHtml))
{
mailMessage.Body = resultText;
}
else
{
mailMessage.IsBodyHtml = true;
mailMessage.Body = resultHtml;
if (!string.IsNullOrEmpty(resultText))
{
using (var contentStream = new MemoryStream(Encoding.UTF8.GetBytes(resultText)))
mailMessage.AlternateViews.Add(new AlternateView(contentStream, text/plain));
}
}
return mailMessage;
}
The first thing we want to do, is to tell RazorEngine to use our own custom Template class:
var config = new TemplateServiceConfiguration { BaseTemplateType = typeof(MvcTemplateBase<T>) };
Now let’s go ahead and define the MvcTemplateBase class:
///<summary>
/// Provides a base implementation of an MVC-compatible template.
///</summary>
public abstract class MvcTemplateBase<T> : TemplateBase<T>
{
public IEncodedString EmbedCss(string path)
{
// load the contents of that file
string cssText;
try
{
cssText = File.ReadAllText(path);
}
catch (Exception)
{
// blank string if we can't read the file for any reason
cssText = "";
}
return Raw(cssText);
}
}
Our class is quite simple – it’s an abstract class that inherits from TemplateBase, and adds any utility method we need. Instead of a utility method, you can easily add a property to a utility class, such as Html, or Url. In our case, we’ve added a method that loads the content of a file, and output it as raw data. Finally, let’s look at how our new template look like:
@inherits Namespace.MvcTemplateBase<Namespace.ResetViewModel>
<!DOCTYPE html>
<html lang="en">
<head>
<title>Custom Template sample</title>
@EmbedCss("Content/bootstrap.min.css")
</head>
<body>
<div class="container">
<div class="hero-unit">
<h1>Reset Password Request</h1>
<p>You requested to reset your password. Please click the following link to start the password reset process:</p>
<p>
<a class="btn btn-primary btn-large" href="@Model.Url">Reset Password</a>
</p>
</div>
</div>
</body>
</html>
As you can see, we have a simple html. Just like in ASP.Net, we use the @inherit keyword to declare the view inherits from MvcTemplateBase, and uses the ResetViewModel as our model. In the view itself, we can use the EmbedCss utility method by calling @EmbedCss(‘file path‘).
We can also use out model, by calling @Model – just like in ASP.Net MVC.