Using XSLT as email template engine in C#

Email has been (and will be for some time) one of the main means to communicate with your customers and perform various core business and security tasks (such as confirming a newly created accounts, helping a user reset their lost password, notify updates and required actions, etc.). These emails usually consist of static sections and some dynamic parts that are specific to the user receiving the email.

Sometimes, a simple string replacement approach works to achieve such goal (that’s what I used to do before). But if you need something more elegant and powerful than that, a good option would be using XSLT. I am no XSLT expert and I won’t talk about it in this post, but I encourage you to learn about it if you don’t already know. In order to follow the principle of separation of concerns and improve testability, the solution is separated into four components with their corresponding interface (contract):

  • A XSLT template compiler (ITemplateCompiler). A simple wrapper that uses cached XslCompiledTransform‘s.
  • An email sender (IEmailSender). Another wrapper, in this case, around the SmtpClient. This is abstracted away in order to mock the actual sending of the email when testing (dump the result to console or to a text file, etc.).
  • A custom XML serializer (IXmlSerializer). Why not use the built in XML serializer? Simple: it doesn’t work with anonymous objects. Sometimes we want to pass our variables without having to explicitly create a class for it. In case you do want to use the regular serializer, you can always create a wrapper that implements IXmlSerializer.
  • A template email sender (ITemplateEmailSender). Integrates all the above mentioned services.

The XSLT compiler

Not much to say about it. It will accept an input XML stream (this would be your variables object serialized as XML), an XSLT file path (or stream), and an output stream to dump the resulting transformation. If you use the overload that accepts the XSLT file path, the XslCompiledTransform object will be cached.

The email sender

Again, as simple as it sounds. Just to decouple the actual sending of the email. In the example, I dump the result to an HTML file called output.html.

The XML Serializer

For the custom XML serializer, I borrowed Martin Normark‘s solution, but made some modifications to it, mainly allowing for the serialization of any kind enumerable, not only arrays.

Basically, it will turn any object into XML following these rules:

  1. If no root element name is provided, “object” will be used.
  2. All properties will be serialized as XML nodes with the same name as the property.
  3. For collection properties, the main node will be named after the property, and the child nodes will have the same name with the suffix “Item” appended.

The template email sender

This is the one that puts all together, and has dependencies to everything else. It only has a Send method (and its async counterpart). You’ll notice that it does not accept a from parameter. That’s because you usually handle that in the SMTP configuration part of your project’s web.config or app.config. If you need it, just go ahead and add it.

Additionally, this service has a LayoutFilePath property. Inspired by ASP .NET’s layout (or master) pages, only much simpler, this allows to have a base, static HTML content file where you can put the frame and layout that is common to all the emails that you will send. If this property is null, then the output will be only what results from the XSLT transformation. The only requirement for your layout file is that you need to include the following wherever you want the content placed:

<!-- Content -->

For example:

<html>
<head>
</head>
<body>
<div style="height: 10px; font-size: 10px; line-height: 10px;">&nbsp;</div>
<table width="602" border="0" cellspacing="0" cellpadding="0" align="center">
<tbody>
<tr>
<td>
<!-- Content --></td>
</tr>
</tbody>
</table>
<div style="height: 10px; font-size: 10px; line-height: 10px;">&nbsp;</div>
</body>
</html>

Putting it all together

var templateDirectory = Path.Combine(Environment.CurrentDirectory, "Templates");
var layoutFile = Path.Combine(templateDirectory, "layout.html");
var xsltFilePath = Path.Combine(templateDirectory, "ActivateAccount.xslt");
var variables = new
{
FirstName = "Axel",
LastName = "Zarate",
Username = "azarate",
Logo = "http://www.logotree.com/images/single-logo-design/logo-design-sample-14.jpg",
ActivationLink = "http://localhost/Account/Activate/azarate"
};

var templateEmailSender = new TemplateEmailSender(emailSender, templateCompiler, xmlSerializer)
{
LayoutFilePath = layoutFile
};

templateEmailSender.Send(xsltFilePath, variables, "axel.zarate@mail.com", "This is a template test");

Advice: To maximize email viewing compatibility across different clients, use regular tables for layout and old HTML attributes for appearance (width, bgcolor, etc.).

Check out the source code and sample.

Dependency injection in ASP .NET MVC with Autofac

Dependency injection (DI) is one form of inversion of control, which is a technique used to reduce coupling between components by replacing hard-coded dependencies with abstractions (usually interfaces) that are passed (injected) to the consuming component.

DI offers a number of benefits and encourages good practices that result in other benefits, such as:

  • Modularity: dependency injection practices favor a more modular application design.
  • Simplified Unit testing
  • Dynamic behavior: allows the changing of concrete implementations of services at runtime or compile time.
  • Scalability
  • Decoupling
  • Service life-cycle management: service containers can take care of the creation, sharing, and disposal of object instances when needed (i.e., we don’t need to call IDisposable.Dispose ourselves).

There are many CI containers out there, but today I will talk about one that I like in particular because it’s simple, flexible and light: Autofac. More specifically, I will show you how you can use it in your ASP .NET MVC projects.

We’ll start by creating an MVC project in Visual Studio (in this case, MVC 4). Choose the template that best suits your needs; in this example I chose the Basic template and I called it AutofacExample. Open the Package Manager Console and execute the following command to install Autofac for MVC 4:

Install-Package Autofac.Mvc4

(You can use the Manage NuGet Packages option, and then search for Autofac MVC4, if you’re more comfortable with the UI version.)

Suppose we already have a few business entities, including Customer. Let’s start by defining some simple services (interfaces and implementation).

using System.Collections.Generic;
using AutofacExample.Models;
 
namespace AutofacExample.Services
{
	public interface IRepository<T> where T : class
	{
		IEnumerable<T> All();
 
		T Get(int id);
 
		void Update(T entity);
 
		void Delete(int id);
	}
 
	public interface ICustomerRepository : IRepository<Customer>
	{
		IEnumerable<Receipt> GetReceipts(int customerId);
	}
 
	public class CustomerRepository : ICustomerRepository
	{
		public IEnumerable<Customer> All()
		{
			// Code goes here
		}
 
		public Customer Get(int id)
		{
			// Code goes here
		}
 
		public void Update(Customer entity)
		{
			// Some code
		}
 
		public void Delete(int id)
		{
			// Code goes here
		}
 
		public IEnumerable<Receipt> GetReceipts(int customerId)
		{
			// Code goes here
		}
	}
}

Next, in our MvcApplication class (in the Global.asax.cs file), we create a RegisterServices method, which we’ll invoke in Application_Start:

private static void RegisterServices()
{
	var builder = new ContainerBuilder();
	var assembly = Assembly.GetExecutingAssembly();

	// Tell autofac to scan the assembly and register all subclasses of System.Web.Mvc.Controller 
	builder.RegisterControllers(assembly);

	// Register repository, and expose it only through the ICustomerRepository interface
	builder.RegisterType<CustomerRepository>()
		.As<ICustomerRepository>().InstancePerHttpRequest();
 
	// Build the container and set it as the default dependency resolver
	var container = builder.Build();
	var resolver = new AutofacDependencyResolver(container);
	DependencyResolver.SetResolver(resolver);
}

(You will need to add using statements for Autofac and Autofac.Integration.Mvc.)

Notice we declared our repository’s lifetime as per HTTP request. This means that the container will dereference the instance after the request has completed so that it can be garbage-collected. If the service implements the IDisposable interface, the Dispose method will be invoked before the instance is released.

Finally, we can add a CustomerController (or use the default HomeController) to consume our newly created CustomerRepository, through its interface. The controller will declare a constructor dependency to ICustomerRepository and Autofac will take care of resolving and instantiating the dependencies and the controller itself.

using AutofacExample.Services;
using System.Web.Mvc;
 
namespace AutofacExample.Controllers
{
	public class CustomerController : Controller
	{
		private readonly ICustomerRepository _customerRepository;
 
		public CustomerController(ICustomerRepository customerRepository)
		{
			_customerRepository = customerRepository;
		}
 
		public ActionResult Index(int id)
		{
			var customer = _customerRepository.Get(id);
			return View(customer);
		}
	}
}

This is a ridiculously simple example, but in a real life application, dependencies would be nested in many levels. For example, our CustomerRepository could have a dependency to a DataService, which in turn may declare dependencies to other services. Autofac will kindly take care of all that mess and deliver what we ask for (as long as all objects involved are properly registered and configured).

Usually, an application may use many services and registering them one by one would be tedious and error prone. But if we use some naming standards for our services we can use assembly scanning and register many at once. For example:

var assembly = Assembly.GetExecutingAssembly();
// Assuming all repository names end with Repository
builder.RegisterAssemblyTypes(assembly)
	.Where(t => t.Name.EndsWith("Repository"))
	.AsImplementedInterfaces();

If you need more control over how a specific service is instantiated, you can specify it:

// Use the connection string named DefaultConnection
builder.Register(d => new Database("DefaultConnection"))
	.As<IDatabase>().InstancePerHttpRequest();

There are many more tips and tricks when using Autofac as your dependency injection container in ASP .NET MVC. Stay tuned.

Model validation filter in ASP .NET Web API

Most Web applications need to be able to accept and save data, and any serious application must perform all sorts of validations before taking information and attempt to store it. Luckily for us (.Net developers at least), the days of manual, imperative validation are gone for good.

Thanks to Data Annotations, model validation and error messages have become easy and consistent. We can pick from the built in validation attributes in the System.ComponentModel.DataAnnotations namespace (such as RequiredAttribute, StringLengthAttribute, CompareAttribute) or roll our own, and then declare our intention to validate our objects properties by decorating them with the corresponding attributes. This validation mechanism is plugged right into the core of ASP NET MVC and Web API, so we can check right away if a model entity passed to a controller action is valid or not:

// MyModel.cs file
using System.ComponentModel.DataAnnotations;

public class MyModel
{
	[Required(ErrorMessageResourceType = typeof(Resources), ErrorMessageResourceName = "MyModel_Name")]
	public string Name { get; set; }

	[EmailAddress]
	public string Email { get; set; }
}

// MyController.cs file
using System.Web.Http;

public class MyController : ApiController
{
	public HttpResponseMessage Post(MyModel model)
	{
		if (ModelState.IsValid)
		{
			// Work with the object
			_repository.Save(model);
			return new HttpResponseMessage(HttpStatusCode.OK);
		}
		else
		{
			var errors = ModelState.Values.SelectMany(v => v.Errors.Select(e => e.ErrorMessage)).ToArray();
			return Request.CreateResponse(HttpStatusCode.BadRequest, new { errors });
		}
	}
}

Easy, huh? But, if you are as lazy (or practical) as me, and don’t want to keep checking your model validity in every action, you can centralize that logic in only one place and then apply it wherever you like. Just create an ActionFilterAttribute:

using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http.Controllers;
using System.Web.Http.Filters;

public class ModelValidationFilterAttribute : ActionFilterAttribute
{
	public override void OnActionExecuting(HttpActionContext actionContext)
	{
		if (!actionContext.ModelState.IsValid)
		{
			var errors = actionContext.ModelState.Values.SelectMany(v => v.Errors.Select(e => e.ErrorMessage)).ToArray();
			actionContext.Response =
				actionContext.Request.CreateResponse(HttpStatusCode.BadRequest, new { errors });
		}
	}
}

And on your controllers:

public class MyController : ApiController
{
	[ModelValidationFilter]
	public HttpResponseMessage Post(MyModel model)
	{
		// No need to check for validity (if model is not valid, the method will not be called)
		_repository.Save(model);
	}
}

Parameter validation in ASP .NET MVC 4

Routing in ASP .NET MVC is a great feature. Among other things, it lets you create stateless applications more easily and in a more elegant way and break away from practices that rely on cookies/session variables. If you have a controller action like the following:

public class SiteController : Controller
{
	public ActionResult News(int id)
	{
		// Do some interesting stuff with that id parameter
	}
}

And if you leave the default route that comes with most MVC project templates, you will have that action automatically respond to a route (read URL) like /Site/News/1. How cool is that?

However, there’s a small catch in the route-matching mechanism. If the route is requested with an invalid id parameter (as in /Site/News/blah) or a missing one (/Site/News) you will get an awful error:

System.ArgumentException: The parameters dictionary contains a null entry for parameter ‘id’ of non-nullable type ‘System.Int32’ for method ‘System.Web.Mvc.ActionResult News(Int32)’ in ‘Tbt.Controllers.SiteController’. An optional parameter must be a reference type, a nullable type, or be declared as an optional parameter.

Yep, that’s a 500 (Internal Server Error) page. That’s basically because the routing engine could find the controller and the action but had trouble parsing the parameter (that happens to be a value type). That might not sound like a big deal (and probably isn’t in most projects); after all, who will be using our web app’s URLs in ways they’re not intended to be used? Well, in my experience, search engines’ crawlers seem to do that. And if good SEO is a concern, you might not want to make the search engines “think” your app crashes for no apparent reason.

Of course, there’s an easy, straightforward way to fix that. You guessed right: make the parameters nullable.

public class SiteController : Controller
{
	public ActionResult News(int? id)
	{
		if (!id.HasValue)
		{
			// Redirect or return the appropriate HTTP code here
		}
		int realId = id.Value;
		// Do some interesting stuff with the realId variable
	}
}

However, depending on the amount of actions the application may have, this can become a cumbersome, tedious task and can distract us from our main goal: write awesome code. That’s what made me look for a better solution, and this is what I came up with.

Using the ActionMethodSelectorAttribute class

According to the MSDN documentation, the ActionMethodSelectorAttributeRepresents an attribute that is used to influence the selection of an action method“. And that’s exactly what we will do: intercept the request and make sure it fulfills all the requirements (in this case, having valid values for all non-nullable parameters); if not, the app will automatically issue a 404 (Not found) HTTP status code and our action method will not be called. Here’s the code:

Update (2015-05-27): Added default value check as suggested by Steven Sproat.

using System;
using System.Reflection;
using System.Web.Mvc;

public class NonNullableParametersAttribute : ActionMethodSelectorAttribute
{
	public override bool IsValidForRequest(ControllerContext controllerContext, MethodInfo methodInfo)
	{
		var methodParams = methodInfo.GetParameters();

		foreach (var parameterInfo in methodParams)
		{
			if (parameterInfo.HasDefaultValue)
			{
				continue;
			}

			var paramType = parameterInfo.ParameterType;
			if (!IsSimpleType(paramType))
			{
				continue;
			}

			var value = controllerContext.Controller.ValueProvider.GetValue(parameterInfo.Name);
			if (value == null || value.AttemptedValue == null || !CanParse(value.AttemptedValue, paramType, value.Culture))
			{
				return false;
			}
		}

		return true;
	}

	private static bool IsSimpleType(Type t)
	{
		return t.IsPrimitive || t.IsEnum || t == typeof(Decimal) || t == typeof(DateTime) || t == typeof(Guid);
	}

	private static bool CanParse(object rawValue, Type destinationType, IFormatProvider formatProvider)
	{
		try
		{
			var test = Convert.ChangeType(rawValue, destinationType, formatProvider);
			return test != null;
		}
		catch
		{
			return false;
		}
	}
}

Then, we decorate our action methods like so:

[NonNullableParameters]
public ActionResult News(int id)
{
	// Do your stuff using that id parameter
}

The NonNullableParametersAttribute will handle any number of parameters of primitive type (int, double, etc) and some non-primitive value types (decimal, DateTime, Guid) for you.

Exporting to CSV in C#

Every once in a while, our application is required to export the data it generates to some sort of format. CSV (comma-separated values) is one of the most popular formats to export/import data.

As the first post of my blog, I will show you a quick way to generate a CSV  file from a generic collection of objects in C#.

Suppose you have a domain object like the following:

using System;
using System.ComponentModel.DataAnnotations;

public class UserDto
{
	public int Id { get; set; }

	[Display(ResourceType = typeof(ModelStrings), Name = "Username", Order = 1)]
	public string Username { get; set; }

	[Required]
	[Display(ResourceType = typeof(ModelStrings), Name = "FirstName", Order = 2)]
	public string FirstName { get; set; }

	[Required]
	[Display(ResourceType = typeof(ModelStrings), Name = "LastName", Order = 3)]
	public string LastName { get; set; }

	[Display(ResourceType = typeof(ModelStrings), Name = "Status", Order = 4)]
	public bool IsActive { get; set; }

	[Display(ResourceType = typeof(ModelStrings), Name = "LastLogin", Order = 5)]
	public DateTime? LastLogin { get; set; }
}

Note: The code above assumes there exists a resource file called ModelStrings with all the specified entries (Username, FirstName, etc.)

Then we can convert a collection of such objects (or objects of any class) using this helper class:

Update (8/7/2014): Based on Goody’s feedback, I decided to add code to handle special characters properly.

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;

namespace AxSoft.Data
{
    public static class CsvHelper
    {
        private const string Quote = "\"";
        private const string EscapedQuote = "\"\"";
        private static readonly char[] EscapableCharacters = { '"', ',', '\r', '\n' };

        public static void ToCsv<T>(IEnumerable<T> collection, Stream stream, params string[] onlyFields) where T : class
        {
            Dictionary<PropertyInfo, string> fieldNames = null;
            var sw = new StreamWriter(stream, Encoding.UTF8);

            foreach (var item in collection)
            {
                // Only on the first iteration we get the list of properties from the object type
                // We use a dictionary of <PropertyInfo, string> instead of just a list of PropertyInfo, 
                // because we extract the display name of the property (if exists) to use it as the "column" header
                if (fieldNames == null)
                {
                    fieldNames = GetProperties(typeof(T), onlyFields);
                    // Write the column headers
                    WriteRow(sw, fieldNames.Select(v => v.Value));
                }

                var current = item;
                var valueList = fieldNames.Keys.Select(prop => prop.GetValue(current, null))
                    .Select(Convert.ToString);

                WriteRow(sw, valueList);
            }

            // Reset the stream position to the beginning
            stream.Seek(0, SeekOrigin.Begin);
        }

        private static Dictionary<PropertyInfo, string> GetProperties(Type type, string[] onlyFields)
        {
            var properties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.FlattenHierarchy)
                                 .Where(prop => IsSimpleOrNullableType(prop.PropertyType))
                                 .OrderBy(prop =>
                                     {
                                         var displayAttr = prop.GetCustomAttributes(typeof(DisplayAttribute), true).FirstOrDefault() as DisplayAttribute;
                                         return displayAttr != null ? displayAttr.Order : int.MaxValue;
                                     });

            // If the entity has MetadataTypeAttribute's, use them
            var metadata = (MetadataTypeAttribute[])type.GetCustomAttributes(typeof(MetadataTypeAttribute), true);

            var names = new Dictionary<PropertyInfo, string>();
            foreach (var property in properties)
            {
                if (onlyFields.Length == 0 || onlyFields.Contains(property.Name, StringComparer.InvariantCultureIgnoreCase))
                {
                    var text = GetDisplayName(property, metadata);

                    names.Add(property, text);
                }
            }

            return names;
        }

        private static string GetDisplayName(PropertyInfo property, IEnumerable<MetadataTypeAttribute> metadata)
        {
            // Extract the display name from the DisplayAttribute on the object or on any of the MetadataTypeAttribute's 
            // it may contain
            var displayText = metadata.Select(m => m.MetadataClassType.GetProperty(property.Name))
                    .Where(p => p != null)
                    .SelectMany(p => (DisplayAttribute[])p.GetCustomAttributes(typeof(DisplayAttribute), true))
                    .Concat((DisplayAttribute[])property.GetCustomAttributes(typeof(DisplayAttribute), true))
                    .Select(m => m.GetName())
                    .FirstOrDefault(n => !string.IsNullOrEmpty(n));

            // Return the display text if found, otherwise return the property name
            return displayText ?? property.Name;
        }
 
        private static bool IsSimpleOrNullableType(Type t)
        {
            if (t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Nullable<>))
            {
                t = Nullable.GetUnderlyingType(t);
            }
 
            return IsSimpleType(t);
        }
 
        private static bool IsSimpleType(Type t)
        {
            return t.IsPrimitive || t.IsEnum || t == typeof(string) || t == typeof(Decimal) || t == typeof(DateTime) || t == typeof(Guid);
        }

        private static void WriteRow(TextWriter sw, IEnumerable<string> values)
        {
            int index = 0;
            foreach (var value in values)
            {
                if (index > 0)
                {
                    sw.Write(",");
                }

                WriteValue(sw, value);
                index++;
            }

            sw.Write(Environment.NewLine);
            sw.Flush();
        }

        private static void WriteValue(TextWriter sw, string value)
        {
            bool needsEscaping = value.IndexOfAny(EscapableCharacters) >= 0;

            if (needsEscaping)
            {
                sw.Write(Quote);
                sw.Write(value.Replace(Quote, EscapedQuote));
                sw.Write(Quote);
            }
            else
            {
                sw.Write(value);
            }
        }
    }
}

This helper class has the following features:

  1. Uses the user-friendly display name of the property if present (DisplayAttribute.Name property).
  2. Respects the order of the properties/columns (DisplayAttribute.Order property).
  3. Uses the DisplayAttribute from the class itself or from the MetadataTypeAttribute the class it’s decorated with (if any).

Note: The onlyFields params array lets us specify which properties we want to output to the CSV. If you want to include them all, just leave that empty.

Streams are used because they give us more control over where we want the results dumped, but if we want to get the resulting CSV as a string, we can add the following method:

public static string ToCsv<T>(IEnumerable<T> collection, params string[] onlyFields) where T : class
{
    using (var stream = new MemoryStream())
    {
        ToCsv(collection, stream, onlyFields);
        using (var reader = new StreamReader(stream))
        {
            return reader.ReadToEnd();
        }
    }
}

Finally, we can consume our helper class in ways like the following:

As a download in ASP .NET MVC

List<UserDto> users = /* Fetch the object list here */;
var outputStream = new MemoryStream();
CsvHelper.ToCsv(users, outputStream);
return File(outputStream, "text/csv", "Users.csv");

As a local file

List<UserDto> users = /* Fetch the object list here */;
using (var fileStream = File.Create("myFile.csv"))
{
	CsvHelper.ToCsv(users, fileStream);
}