4
\$\begingroup\$

So here we are, using a StringBuilder to build an email body. I know there's a lot on StackOverflow and endless debate/discussion around how best to concatenate strings.

  • Can this be done in fewer lines of code in C#?
  • Can this be done better using templating?

My goals are readability and maintainability.

StringBuilder msgBody = new StringBuilder();
msgBody.AppendLine("Deleted Order Item Information");
msgBody.AppendLine("------------------------------------");
msgBody.AppendLine();
msgBody.AppendLine("Delete Date:    {0}".FormatWith(orderDetail.DeletedDate.FormatDateTime(dtFormat)));
msgBody.AppendLine("Delete Comment: {0}".FormatWith(orderDetail.DeletedComment));
msgBody.AppendLine();
msgBody.AppendLine("Order #:        {0}".FormatWith(order.ID.ToString()));
msgBody.AppendLine("Order Date:     {0}".FormatWith(order.SubmitDate.FormatDateTime(dtFormat)));
msgBody.AppendLine("Order Name:     {0}".FormatWith(order.Name));
msgBody.AppendLine("Order Comment:  {0}".FormatWith(order.Comment));
msgBody.AppendLine("Department:     {0}".FormatWith("{0} - {1}".FormatWith(orderDetail.Department, orderDetail.DepartmentDesc)));
msgBody.AppendLine();
msgBody.AppendLine("Item Number:    {0}".FormatWith(orderDetail.StockNumber));
msgBody.AppendLine("Quantity:       {0}".FormatWith(orderDetail.Quantity));
msgBody.AppendLine("Rush:           {0}".FormatWith((orderDetail.Rush.ToYesNo())));
msgBody.AppendLine("Item Name:      {0}".FormatWith(item.Name));
msgBody.AppendLine("Item Desc:      {0}".FormatWith(item.Description1));
msgBody.AppendLine("                {0}".FormatWith(item.Description2));
msgBody.AppendLine("Stock:          {0}".FormatWith((orderDetail.Stock.ToYesNo())));
msgBody.AppendLine("Item Comment:   {0}".FormatWith(orderDetail.Comment));
\$\endgroup\$

2 Answers 2

6
\$\begingroup\$

I have used one template engine in by name DotLiquid to resolve similar problems.

  1. Readability: You have to extract your message template from the code to separate file. The template itself will lives its own life, usually independently from the code.
  2. Maintainability:
    • Collect all required parameters and conditions in one place. Having conditions in your message tends to be next step in real message processing. By the way, anonymous classes from DotLiquid work well with your .
    • Then: template processing, message composing, and and putting it to queue to sent it. Sending operation itself could be time consuming and quite tricky

Thus I have handled hundreds of template based messages with rich HTML per day. Obviously, if you're going to write next smtp monster, you'll write a more perfomance optimal solution. But using such template engine is good place to start.

And here is a code snippet:

// Template itself, assume that is has been loaded from file
var messageTemplate = 
@"Deleted Order Item Information
------------------------------------ 

Delete Date:    {{Date}}
Delete Comment: {{DeletedComment}}
… other text";

// Parses and compiles the template
var template = DotLiquid.Template.Parse(messageTemplate);

// Renders the output
var messageBody = template.Render(DotLiquid.Hash.FromAnonymousObject(
    // Parameters
    new {
        Date = DateTime.Today,
        DeletedComment = "Some Comment"
    }));
\$\endgroup\$
0
\$\begingroup\$

Take a look at: http://razorengine.codeplex.com/

As they say it is: "A templating engine built upon Microsoft's Razor parsing technology."

Quick example:

var modelData = new { Name = "Cookie Monster", Message = "Cookieees!!!" };
string template = "@Model.Name says: '@Model.Message'";
string result = Razor.Parse(template, modelData);

//result: Cookie Monster  says: 'Cookieees!!!'

And of course you can have razor script files (*.cshtml) and maybe use them something like this:

    var modelData = new { Name = "Cookie Monster", Message = "Cookieees!!!" };
    string template = File.OpenText(Server.MapPath("~/templates/template.cshtml")).ReadToEnd();
    string result = Razor.Parse(template, modelData);
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.