Monthly Archives: November 2012

Formatting email HTML with T4 templates

There’s several techniques available to a .Net developer to properly format HTML outside web pages. One of them is actually using an HTML view render engine like Razor to format it.

The one I find the cleaner and easier to maintain is using T4 templates. Since this is a post about T4, I suggest that you take a loot at my T4 Templates page before moving on, to get used to the code reading.

The full demo project can be downloaded here

Project Structure

blog17

The simple demo project is composed of two T4 Runtime Templates:

  • EmailTemplate defines and transforms the default HTML template.
  • The BodyTemplate defines and transforms the HTML that composes the “Body” of the email.

The entry point for this template transformation is on the MailExtensions.cs file and written as extensions to MailMessage. The Program.cs file just contains enough code to setup an email message and call the template entry point

class Program
{
    static void Main(string[] args)
    {
        var mail = new MailMessage
        {
            From = new MailAddress("me@mycompany.com", "Me AndMe"),
            Subject = "Me poking You",
            Body = string.Empty
        };

        mail.To.Add("someemail@somecompany.com");

        var template = new BodyTemplate
                            {
                                FirstName = "You",
                                LastName = "AndYou"
                            };

        mail.CreateHtmlBody(template);

        using (var client = new SmtpClient())
        {
            client.SendAsync(mail, null);
        }
    }
}

The email is just setup to be delivered to a static folder in the app.config file

<system.net>
    <mailSettings>
        <smtp deliveryMethod="SpecifiedPickupDirectory">
            <specifiedPickupDirectory pickupDirectoryLocation="D:\Mail" />
        </smtp>
    </mailSettings>
</system.net>

T4 Runtime Templates

To create a T4 Runtime Template all you have to do is Add New Item, then select the Runtime Text Template Item.

blog18

What this template does is generate a C# class that you can use at Run-Time to transform and generate it’s output. You can either pass parameters to these templates by using their built in T4 Parameter Directive or simply by extending the generated partial class. I prefer extending the generated class as it makes it more unit testable when required, so I used this approach in the demo code.

This type of templates ignores some of the T4 Directives, however some of them are put to good use to trick the editor into proper syntax highlighting. I use the T4 Output Directive to make tangible syntax highlight my HTML, for some reason at the time of this post, tangible didn’t highlight it with “.html” so “.xml” had to do the trick.

<#@ output extension=".xml" #>

The EmailTemplate

The template itself is very simple, containing very simple HTML. This should contain the default style template for your emails, with a proper Header, Footer and common sections in all your emails.

<#@ template language="C#" #>
<#@ output extension=".xml" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Collections.Generic" #>
<html>
  <body>
    <h1>This is a header</h1>
    <div>
		<#= GetBodyText() #>
    </div>
    <h1>This is a footer</h1>
</body>
</html>

The generated class partial definition contains the method used by the template to generate the Body. This method supports both a Body string and a Body object that will be verified as being another valid template. So if it get’s another template it will attempt to render it, while if it get’s a string it will just dump it.

public partial class EmailTemplate
{
    public string Body { get; set; }

    private object _bodyTemplate;
    public object BodyTemplate
    {
        get { return _bodyTemplate; }
        set
        {
            // Get the type and the TransformText method using reflection
            var type = value.GetType();
            var method = type.GetMethod("TransformText");

            // Reflection signature checks
            if (method == null) throw new ArgumentException("BodyTemplate needs to be a RunTimeTemplate with a TransformText method");
            if (method.ReturnType != typeof(string) || method.GetParameters().Any()) throw new ArgumentException("Wrong TransformText signature on the BodyTemplate");

            // If everything is ok, assign the value
            _bodyTemplate = value;
        }
    }

    private string GetBodyText()
    {
        var result = string.Empty;

        // Use the BodyTemplate if available
        if(BodyTemplate != null)
        {
            dynamic castTemplate = BodyTemplate;
            result = castTemplate.TransformText();
        }
        // Otherwise use the Body string if it's not null or empty
        else if(!string.IsNullOrEmpty(Body))
        {
            result = Body;
        }

        return result;
    }
}

The BodyTemplate

The BodyTemplate is a very simple template just to show the linear transformation of both templates and the inclusion of email specific fields for email customization.

<#@ template language="C#" #>
<#@ output extension=".xml" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Collections.Generic" #>
<p>Hi there <#= FirstName #> <#= LastName #></p>
<p>This is an Example of a Body.</p>

It’s extension only contains properties so that we can configure the email Body.

public partial class BodyTemplate
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

The Entry Point – MailExtensions

The wrapper methods that manage the main template transformations are in the MailExtensions.cs file and are written as extension methods, one for a using a Body string and another one for using a Body template. This demo however doesn’t make any use of the Body string, it only uses a Body template.

public static class MailExtensions
{
    public static void CreateHtmlBody(this MailMessage message, string body)
    {
        var mailTemplate = new EmailTemplate { Body = body };
        var html = AlternateView.CreateAlternateViewFromString(mailTemplate.TransformText(), Encoding.UTF8, "text/html");
        message.AlternateViews.Add(html);
    }

    public static void CreateHtmlBody(this MailMessage message, object template)
    {
        var mailTemplate = new EmailTemplate { BodyTemplate = template };
        var html = AlternateView.CreateAlternateViewFromString(mailTemplate.TransformText(), Encoding.UTF8, "text/html");
        message.AlternateViews.Add(html);
    }
}

Async integration with SalesForce Leads web service

The SalesForce Leads web service is used mainly to register new leads from other applications, for example a trial page where a user registers for a trial and a Lead in SalesForce is created to be followed by commercial teams.

The integration itself is very simple and straightforward, this post is about doing it in an async way, and also presents a solution for integrations with several different Models.

The web service is called through a normal HttpWebRequest object, but it’s setup is done in 3 stages:

  • The creation of the HttpWebRequest with the initial configuration.
  • Writing the RequestStream from a string – This is the service’s parameters that will be sent in the HTTP POST.
  • Submiting the request.

The RequestStream writing and the request submission are written as async ready methods (they can be awaited on) but the HttpWebRequest creation isn’t as this is of very fast execution.

Calling the service through the HttpWebRequest in an async manner

The integration is written in a static class. The entry point is the static method SubmitRequest, it takes as a parameter an object that is basically a Model object that will have it’s metadata parsed for Param attributes to get the SalesForce common parameters.

public static async Task SubmitRequest(object info)
{
    var request = CreateSalesForceRequest();
    var message = GetSalesForceParams(info) + "&" + GetSalesForceStaticParams();

    await request.WriteRequestStream(message);

    try
    {
        await request.SubmitSalesForce();
    }
    catch (Exception)
    {
        // This doesn't seem to do anything as the servlet allways returns HTTP 200.OK.
        // Use the debug email param and debug param on the servlet Parameter list instead.
        Trace.TraceError("Error registering lead in salesforce. Encoded message string was: {0}", message);
    }
}

Besides the GetSalesForceParams, we can see the 3 stages described earlier in the following methods:

private static HttpWebRequest CreateSalesForceRequest()
{
    var request = (HttpWebRequest)WebRequest.Create(ConfigurationManager.AppSettings["SalesforceWebToLeadUrl"]);
    request.Timeout = 60000;
    request.ContentType = "application/x-www-form-urlencoded";
    request.Method = WebRequestMethods.Http.Post;
    request.KeepAlive = true;
    request.ProtocolVersion = HttpVersion.Version11;
    request.UserAgent = "";

    return request;
}

This creates the HttpWebRequest properly configured to call the Leads web service. The specific web service URL is being retrieve from the configuration file.

private static Task WriteRequestStream(this WebRequest request, string message)
{
    return Task.Factory.FromAsync<Stream>(request.BeginGetRequestStream, request.EndGetRequestStream, null)
        .ContinueWith(t =>
                            {
                                var stream = t.Result;
                                var data = Encoding.ASCII.GetBytes(message);
                                Task.Factory.FromAsync(stream.BeginWrite, stream.EndWrite, data, 0, data.Length,
                                                        null, TaskCreationOptions.AttachedToParent)
                                    .ContinueWith(x => stream.Close());
                            });
}

This is the first of the async ready methods. It is written as an extension to the WebRequest object. It returns a Task so that it can be awaited and uses the useful FromAsync method in the TPL that wraps a pair of begin and end methods.

private static Task SubmitSalesForce(this WebRequest request)
{
    return Task.Factory.FromAsync<WebResponse>(request.BeginGetResponse, request.EndGetResponse, null)
        .ContinueWith(t =>
                            {
                                var response = t.Result;
                                if (response != null)
                                    response.Close();
                            });
}

The last stage of the request submission is the actual SubmitSalesForce method. It is written as an extension to the WebRequest object.

Formatting the service’s parameters

The request string is composed by 2 different blocks. The first one will compose the static parameters with the Leads group, your company OID in SalesForce and additional things that you might want to setup. These are saved in a static Dictionary

private static readonly Dictionary<string, string> StaticParams = new Dictionary<string, string>
                                                                        {
                                                                            {"oid", "MYOID"},
                                                                            {"lead_source", "Web Trial"},
                                                                            {"debug", "1"},
                                                                            {
                                                                                "debugEmail",
                                                                                "me@mycompany.com"
                                                                            }
                                                                        };

And then transformed by the simple method

private static string GetSalesForceStaticParams()
{
    return string.Join("&", StaticParams.Select(p => p.Key + "=" + HttpUtility.UrlEncode(p.Value)));
}

The tricky part comes from the non-static parameters. In my scenario I have several projects using this integration with SalesForce, and these projects use different types of Models and Model architectures. To cope with these differences I used an attribute decoration pattern, much like ADO.NET does validation, so that Models could be decorated specifying certain properties as SalesForce parameters. An extra degree of complexity is added because I have to support EntityFramework Database first modelling, so property decoration is done through the MetadataType attribute instead of having metadata at the properties themselves, an example of an extension of an EntityFramework Database first model object is given below:

[MetadataType(typeof(LandingPageUserMetadata))]
public partial class LandingPageUser
{
}

public class LandingPageUserMetadata
{
    [Required]
    [Display(Name = "First Name")]
    [SalesForceParam(Type = SalesForceParamType.FirstName)]
    public string FirstName { get; set; }

    [Required]
    [Display(Name = "Last Name")]
    [SalesForceParam(Type = SalesForceParamType.LastName)]
    public string LastName { get; set; }

    [Required]
    [Display(Name = "Email account")]
    [EmailValidation(ErrorMessage = "This has to be a valid email address.")]
    [SalesForceParam(Type = SalesForceParamType.Email)]
    public string EmailAddress { get; set; }
}

To support this type of decoration, additional code needs to be written to check for the MetadataType attribute and then parse it’s configured Type. Then the mapping between the actual metadata and the properties needs to be in place so that the values are retrieved from the Model object and not the object used to define the metadata.

The code that takes an object and parses it’s metadata or metadatatype attribute and returns a request message string is:

public static string GetSalesForceParams(object info)
{
    var sfProperties = info.GetType()
        .GetProperties()
        .Where(p => p.GetCustomAttributes(typeof(SalesForceParamAttribute), true).Any())
        .ToArray();

    if (!sfProperties.Any())
    {
        var metadataTypes = info.GetType()
            .GetCustomAttributes(typeof(MetadataTypeAttribute), true)
            .OfType<MetadataTypeAttribute>()
            .ToArray();

        var metadata = metadataTypes.FirstOrDefault();

        if (metadata != null)
        {
            sfProperties = metadata.MetadataClassType
                .GetProperties()
                .Where(p => p.GetCustomAttributes(typeof(SalesForceParamAttribute), true).Any())
                .ToArray();
        }
    }

    var sfParams =
        sfProperties
            .Where(p => info.GetType().GetProperty(p.Name).GetValue(info) != null)
            .Select(
                p =>
                ((SalesForceParamAttribute)p.GetCustomAttributes(typeof(SalesForceParamAttribute), false).First()).SalesForceParam +
                "=" +
                HttpUtility.UrlEncode(info.GetType().GetProperty(p.Name).GetValue(info).ToString()));

    return string.Join("&", sfParams);
}

The attribute definition is simple and straightforward:

namespace IW.Web.Common.SalesForce
{
    using System;

    [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)]
    public class SalesForceParamAttribute : Attribute
    {
        public SalesForceParamType Type { get; set; }

        public string SalesForceParam
        {
            get
            {
                switch (Type)
                {
                    case SalesForceParamType.FirstName:
                        return "first_name";
                    case SalesForceParamType.LastName:
                        return "last_name";
                    case SalesForceParamType.Email:
                        return "email";
                    case SalesForceParamType.Company:
                        return "company";
                    case SalesForceParamType.Phone:
                        return "phone";
                    default:
                        return string.Empty;
                }
            }
        }
    }

    public enum SalesForceParamType
    {
        FirstName,
        LastName,
        Email,
        Company,
        Phone
    }
}

Calling the Async methods from an ASP.NET MVC 4 controller

Whenever you’re calling async methods, that are awaiting method calls, you need to make sure that the controller awaits on them, so that they can be executed to the end within the lifetime scope of the controller, without destroying the thread running the controller.

ASP.NET MVC 2 introduced AsyncController, but then the way we had to use to write async methods was too quirky. With the async framework that was changed and now writing an AsyncController is very clean:

public class HomeController : AsyncController
{
    public ActionResult Index()
    {
        return View(new LandingPageUser());
    }

    [HttpPost]
    public async Task<ActionResult> Index(LandingPageUser model)
    {
        // Check if the model is valid and try to Save it to the Database
        if (ModelState.IsValid && model.Save(ModelState))
        {
            // DO YOUR WORK
            // (...)

            // Integrate with SalesForce and send in the request
            if (Boolean.Parse(ConfigurationManager.AppSettings["EnableSalesforceRegistrations"]))
                await SalesForceExtensions.SubmitRequest(model);

            return View("Success");
        }

        return View(model);
    }
}