Friday, 26 November 2010

Sending Templated E-mail using the Spark View Engine

Spark photo © SCholewiak via FlickrWe have a couple of systems that send personalized e-mail notifications to our users, and for a while I’ve been looking for a nice way to use a proper MVC-style view engine to populate the templates for personalizing these e-mails. The problem is, most of the ASP.NET view engines are so tightly bound to System.Web and things like HttpContext.Current and the VirtualPathProvider that running them in a standalone console application is really quite unpleasant.

Well, with a bit of hacking around and some help from @RobertTheGrey, I’ve finally got the awesome Spark view engine running within a console app. No fake VirtualPathProviders, no mocking or spoofing HttpContext.Current – it just works.

The secret is this little snippet of code here:

var templateFolder = @"D:\Templates\";
var viewFolderParameters = new Dictionary<string, string> {
    {"basePath", templateFolder}
};
var settings = new SparkSettings();
settings.SetPageBaseType(typeof(TemplateBase));
settings.AddViewFolder(ViewFolderType.FileSystem, viewFolderParameters);
engine = new SparkViewEngine(settings);

which spins up a fresh SparkSettings configuration object, tells it to use your own TemplateBase class and the templates folder you’ve specified. The method that actually does the population looks like this:

public string Populate(string templateFileName, object data) { 
  var writer = new StringWriter(); 
  var descriptor = new SparkViewDescriptor(); 
  descriptor.AddTemplate(templateFileName); 
  var view = (TemplateBase)engine.CreateInstance(descriptor); 
  try { 
    view.ViewData = new ViewDataDictionary(data); 
    view.RenderView(writer); 
  } finally { 
    engine.ReleaseInstance(view); 
  } 
  return (writer.ToString()); 
}

so you end up with little snippets like this:

foreach(var user in userRepository.RetrieveUsersWhoShouldGetWelcomeEmails()) {
    var htmlBody = templater.Populate("welcome_html.spark”, user):
    var textBody = templater.Populate(“welcome_text.spark”, user):
    mailServer.SendMail(
[email protected]”, user.Email, “Welcome!”, textBody, htmlBody);
}

There’s a full working example in the Spark repository on GitHub if you’re interested.

Spark photo © SCholewiak via Flickr – used under Creative Commons attribution license.

1 comment:

Mike Murray said...

We're doing the same thing and it works great! One thing we ran into is to make sure you don't construct the SparkViewEngine every time when working in a multi-threaded environment, as can happen when coming from ASP.NET or consuming message bus events. There appeared to be some sort of memory leak we ran into if you don't make the construction of the SparkViewEngine into a singleton through the use of an IOC container. One thing we aren't currently doing is the ReleaseInstance call. We'll have to look into that. Thanks for posting.