When it comes to e-mails, nopCommerce has a very flexible Message Templates system to render e-mails by replacing what are called Tokens with actual values. For example, %Customer.FullName% will be replaced by a customer's full name.
While nopCommerce's Message Templates system is flexible enough to handle most scenarios (version 3.50 even supports attaching a static file), there are at least 2 deficiency with the implementation:
- Conditional rendering (if... then... else...) is not allowed
- Common layout has to be copied over to each and every Message Templates
To overcome these shortcomings, we can make use of Microsoft's powerful rendering engine - Razor. I believe most MVC developers are vary familiar with Razor syntax.
Below I'll show a proof-of-concept of using Razor engine to render Message Templates.
Razor-powered Message Templates System
Before I begin, I want to give credit to this article for laying out the foundation for this experiment. While I can't confirm it is the first to introduce the concept, it is what I base my experiment on.
To continue, open up nopCommerce source code using Visual Studio. Continue to launching Package Manager Console and enter Install-Package RazorEngine. Note that you need to do this for both Nop.Services and Nop.Web.
Next, open and edit WorkflowMessageService.cs. Enter the following code as a new C# Method.
Note: You also need to update IWorkflowMessageService.cs with the same Method Signature.
public virtual int SendTestEmail(Customer customer, int languageId)
{
if (customer == null)
throw new ArgumentNullException("customer");
var store = _storeContext.CurrentStore;
languageId = EnsureLanguageIsActive(languageId, store.Id);
var messageTemplate = GetActiveMessageTemplate("Test", store.Id);
if (messageTemplate == null)
return 0;
//email account
var emailAccount = GetEmailAccountOfMessageTemplate(messageTemplate, languageId);
//tokens
var tokens = new List<Token>();
_messageTokenProvider.AddStoreTokens(tokens, store, emailAccount);
_messageTokenProvider.AddCustomerTokens(tokens, customer);
//event notification
_eventPublisher.MessageTokensAdded(messageTemplate, tokens);
var toEmail = emailAccount.Email;
var toName = emailAccount.DisplayName;
return SendNotification(messageTemplate, emailAccount,
languageId, tokens,
toEmail, toName);
}
In the above code, I did not remove the support for existing Token format. So both %Store.Name% and @Store_Name will work. And note that, since Razor syntax views dot (.) as a special character, we replaced dots (.) with underscores (_).
Also in WorkflowMessageService.cs, update SendNotification() by adding:
//Replace subject and body tokens
var subjectReplaced = _tokenizer.Replace(subject, tokens, false);
var bodyReplaced = _tokenizer.Replace(body, tokens, true);
// add these (below)
var viewBag = new RazorEngine.Templating.DynamicViewBag();
foreach (var item in tokens)
viewBag.AddValue(item.Key.Replace(".", "_"), item.Value);
bodyReplaced = RazorEngine.Razor.Parse(messageTemplate.Body, null, viewBag, null);
// add these (above)
var email = new QueuedEmail
{
Priority = 5,
From = emailAccount.Email,
FromName = emailAccount.DisplayName,
Now, open CommonController.cs (the one in Nop.Web project) and enter the following as a new Action Method.
public ActionResult SendTestEmail()
{
var workflowMessageService = EngineContext.Current.Resolve<IWorkflowMessageService>();
workflowMessageService.SendTestEmail(_workContext.CurrentCustomer, _workContext.WorkingLanguage.Id);
return Content("SENT...");
}
This is just a quick way for us to test out the code.
Razor-sharp Message Templates
Now, go to your database, and insert a new Message Template with the system name "Test". Mine looks very simple:
Run the code by navigating to http://localhost:{port}/common/sendtestemail, and the result is promising!
Note that what I am showing here is only the mast basic thing Razor can do. Remember that it can run C# codes if it's written to like so!
Pitfalls of Razor-powered Message Templates
"Is there any disadvantage of this approach?", you asked. And unfortunately, YES!
Because Razor Engine is so powerful, it can actually break things if the end users (and I mean all non-programmer webmasters) doesn't know how to use it properly. For example, @ is a special character, and shall be escaped with @@.
Shall we rewrite nopCommerce's Message Templates to use Razor Engine? Let's discuss!