Category Archives: T4

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);
    }
}

Working with iOS Property Lists using T4

One of the disadvantages on working with on a multi platform project, and one of the other platforms is iOS, is that iOS is considered the main game and everyone else a port. This is our case, so the actual game design and tweaking is being done in a bunch of Property Lists.

So the first thing we have to do is import these files and read them. The property list is nothing more then a XML file with a bunch of properties in it.

Because these files will constantly change throughout the project, and the game designer can decide to add or remove properties from them, I decided that instead of just reading the XML I should also generate a strongly type C# Class representing what I read. This allows me to get compiler errors if someone removes a property I’m using, if someone changes the structure of an array or if someone decides to change a type of a property, because I’m working with a strongly typed class I will get compiler errors warning me of the issue.

You can download the full solution here: PListReader

The solution: Convert the Property Lists to a C# Class

To solve my Property List issues I decided to write a T4 template, that I point to a folder with all the .plist files and it will generate a C# class. The project is setup like this:

plist1

All the Property Lists are in the Configuration folder, the PList.tt is the T4 template, the Plist.cs is the C# class and Program.cs as some prototyping code that I left there because it may be useful to test new template functionality.

To exemplify I will show an example Property List and the resulting C# Class. An example .plist file:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>Structures</key>
	<array>
		<string>well</string>
		<string>toolshed</string>
		<string>storageshed</string>
		<string>field</string>
	</array>
	<key>Seeds</key>
	<array/>
	<key>Clients</key>
	<array/>
	<key>Season</key>
	<integer>0</integer>
	<key>Score</key>
	<integer>1000</integer>
	<key>ScoreExpert</key>
	<integer>1500</integer>
	<key>Time</key>
	<integer>120</integer>
</dict>
</plist>

And the generated C# class:

public static class Level0101
{
	public static string[] Structures { get {
												return new string[] {
													"well",
													"toolshed",
													"storageshed",
													"field",
												};
											} }

	public static int Season { get { return 0 ; } }
	public static int Score { get { return 1000 ; } }
	public static int ScoreExpert { get { return 1500 ; } }
	public static int Time { get { return 120 ; } }
}

Details of the T4 Template

I built the template for the features the game designer is currently using, so I skipped on a lot of Property types that can exist in a Property List. This template is a starting point and not finished work.

The complexity of the template comes from the array type in Property Lists, because the arrays come be of N dimension and because they can contain a mix of types there’s a lot of inspection going on to determine the dimension and if the array is just one type, or several. If we have a mix of several types inside the array we just say it’s an object array.

Of the possible key types in Property Lists, the designer is only using string and integer, so those are the only two that the template looks at.

On the top of the template, the folder where all the .plist files are located is defined, this needs to be changed for each specific scenario.

string[] filepaths = Directory.GetFiles(System.IO.Path.GetDirectoryName(this.Host.TemplateFile) + "\\Configuration", "*.plist");

Reading through a Property List file

The main part of the template, iterates through all the files, reads the contents of each file and parses all the keys:

<#
	foreach(var file in filepaths)
	{
#>
	// From File: <#= file.Substring(file.LastIndexOf("\\") + 1) #>
	public static class <#= FilePath2Class(file) #>
	{
<#
	    XElement plist = XElement.Load(file);
	    XElement plistDic = plist.Elements().Single();

        using (IEnumerator<XElement> enumerator = plistDic.Elements().GetEnumerator())
        {
            while (enumerator.MoveNext())
            {
                if (enumerator.Current.Name != "key") continue;

                string keyName = enumerator.Current.Value;
                enumerator.MoveNext();
                XName typeName = enumerator.Current.Name;
                string typeValue = enumerator.Current.Value;

                if (typeName.ToString() == "array")
                {
					WriteArray(enumerator.Current, keyName);
                }
				else
				{
					WriteType(typeName.ToString(), keyName, typeValue);
				}
            }
        }
#>
	}

<#
	}
#>

Contains a helper function to convert the file name into a class name, it’s not perfect and sometimes will break naming conventions:

string FilePath2Class(string filePath)
{
	var final = filePath.Substring(filePath.LastIndexOf("\\") + 1);
	final = final.Substring(0, final.Length - 6).Replace("_", "");
	final = final[0].ToString().ToUpper() + final.Substring(1);
	return final;
}

When we encounter a key that’s not an array, we use a helper method to write it:

	void WriteType(string type, string name, string typeValue)
	{
		if(type == "string")
		{
#>
		public static string <#= name #> { get { return "<#= typeValue #>" ; } }
<#+
		}
		if(type == "integer")
		{
#>
		public static int <#= name #> { get { return <#= typeValue #> ; } }
<#+
		}
	}

Reading through arrays

Write arrays is composed of 4 methods, one that write an array (the header of the array):

	void WriteArray(XElement element, string key)
	{

		IEnumerable<XElement> descendants = element.Elements();
		XElement firstChild = descendants.FirstOrDefault();
		
		if(firstChild == null) return; // Empty Array
		
		XElement firstTypeIterator = element;
		string firstType = firstType = firstTypeIterator.Name.ToString();
		int depth = 0;

		while(firstType == "array")
		{
			depth++;
			firstTypeIterator = firstTypeIterator.Elements().FirstOrDefault();
			firstType = firstTypeIterator.Name.ToString();
		}

		string arrayType = GetArrayType(element, firstType);
		if(arrayType == "integer") arrayType = "int"; // int normalization, should be done as a method!

#>
		public static <#= arrayType #><#= WriteArrayDimension(depth) #> <#= key #> { get {
													return new <#= arrayType #><#= WriteArrayDimension(depth) #> {
<#+
		WriteArraySet(element);
#>													};
												} }

<#+
	}

One that writes each component of the array:

	void WriteArraySet(XElement element)
	{
		foreach(XElement child in element.Elements())
		{
			string elementType = child.Name.ToString();
			if(elementType == "array")
			{
#>														{
<#+
				PushIndent("\t");
				WriteArraySet(child);
				PopIndent();
#>														},
<#+
			}
			else if(elementType == "string")
			{
#>														"<#= child.Value #>",
<#+
			}
			else if(elementType == "integer")
			{
#>														<#= child.Value #>,
<#+
			}
		}
	}

And two other helper methods, one for finding out the dimension of the array:

	string WriteArrayDimension(int size)
	{
		string result = "[";
		for(int i = 1; i < size; i++) result += ",";
		result += "]";
		return result;
	}

And finally one to determine what should be the type of the array

	string GetArrayType(XElement element, string type)
	{
		IEnumerable<XElement> descendants = element.Elements();
		XElement firstChild = descendants.FirstOrDefault();

		if(firstChild == null) return type; // Empty Array
		string firstType = firstChild.Name.ToString();

		foreach(XElement descendant in descendants)
		{
			if(descendant.Name.ToString() == "array")
			{
				string tmpType = GetArrayType(descendant, type);
				if(tmpType != type) return "object";
			}
			else
			{
				if(descendant.Name.ToString() != type) return "object";
			}
		}

		return type;
	}

The full Template

<#@ template debug="true" hostSpecific="true" #>
<#@ output extension=".cs" #>
<#@ Assembly Name="System.Core.dll" #>
<#@ Assembly Name="System.Xml.dll" #>
<#@ Assembly Name="System.Xml.Linq.dll" #>
<#@ Assembly Name="System.Windows.Forms.dll" #>
<#@ import namespace="System" #>
<#@ import namespace="System.IO" #>
<#@ import namespace="System.Diagnostics" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Xml.Linq" #>
<#@ import namespace="System.Collections" #>
<#@ import namespace="System.Collections.Generic" #>
<#   
	string[] filepaths = Directory.GetFiles(System.IO.Path.GetDirectoryName(this.Host.TemplateFile) + "\\Configuration", "*.plist");
#>
namespace PListReader.Configuration
{
<#
	foreach(var file in filepaths)
	{
#>
	// From File: <#= file.Substring(file.LastIndexOf("\\") + 1) #>
	public static class <#= FilePath2Class(file) #>
	{
<#
	    XElement plist = XElement.Load(file);
	    XElement plistDic = plist.Elements().Single();

        using (IEnumerator<XElement> enumerator = plistDic.Elements().GetEnumerator())
        {
            while (enumerator.MoveNext())
            {
                if (enumerator.Current.Name != "key") continue;

                string keyName = enumerator.Current.Value;
                enumerator.MoveNext();
                XName typeName = enumerator.Current.Name;
                string typeValue = enumerator.Current.Value;

                if (typeName.ToString() == "array")
                {
					WriteArray(enumerator.Current, keyName);
                }
				else
				{
					WriteType(typeName.ToString(), keyName, typeValue);
				}
            }
        }
#>
	}

<#
	}
#>
}
<#+
	string FilePath2Class(string filePath)
	{
		var final = filePath.Substring(filePath.LastIndexOf("\\") + 1);
		final = final.Substring(0, final.Length - 6).Replace("_", "");
		final = final[0].ToString().ToUpper() + final.Substring(1);
		return final;
	}
	
	void WriteType(string type, string name, string typeValue)
	{
		if(type == "string")
		{
#>
		public static string <#= name #> { get { return "<#= typeValue #>" ; } }
<#+
		}
		if(type == "integer")
		{
#>
		public static int <#= name #> { get { return <#= typeValue #> ; } }
<#+
		}
	}

	void WriteArray(XElement element, string key)
	{

		IEnumerable<XElement> descendants = element.Elements();
		XElement firstChild = descendants.FirstOrDefault();
		
		if(firstChild == null) return; // Empty Array
		
		XElement firstTypeIterator = element;
		string firstType = firstType = firstTypeIterator.Name.ToString();
		int depth = 0;

		while(firstType == "array")
		{
			depth++;
			firstTypeIterator = firstTypeIterator.Elements().FirstOrDefault();
			firstType = firstTypeIterator.Name.ToString();
		}

		string arrayType = GetArrayType(element, firstType);
		if(arrayType == "integer") arrayType = "int"; // int normalization, should be done as a method!

#>		public static <#= arrayType #><#= WriteArrayDimension(depth) #> <#= key #> { get {
													return new <#= arrayType #><#= WriteArrayDimension(depth) #> {
<#+
		WriteArraySet(element);
#>													};
												} }

<#+
	}
	
	string WriteArrayDimension(int size)
	{
		string result = "[";
		for(int i = 1; i < size; i++) result += ",";
		result += "]";
		return result;
	}

	void WriteArraySet(XElement element)
	{
		foreach(XElement child in element.Elements())
		{
			string elementType = child.Name.ToString();
			if(elementType == "array")
			{
#>														{
<#+
				PushIndent("\t");
				WriteArraySet(child);
				PopIndent();
#>														},
<#+
			}
			else if(elementType == "string")
			{
#>														"<#= child.Value #>",
<#+
			}
			else if(elementType == "integer")
			{
#>														<#= child.Value #>,
<#+
			}
		}
	}
	
	string GetArrayType(XElement element, string type)
	{
		IEnumerable<XElement> descendants = element.Elements();
		XElement firstChild = descendants.FirstOrDefault();

		if(firstChild == null) return type; // Empty Array
		string firstType = firstChild.Name.ToString();

		foreach(XElement descendant in descendants)
		{
			if(descendant.Name.ToString() == "array")
			{
				string tmpType = GetArrayType(descendant, type);
				if(tmpType != type) return "object";
			}
			else
			{
				if(descendant.Name.ToString() != type) return "object";
			}
		}

		return type;
	}
#>

Conclusion

One of the reasons why this doesn’t feel like final work is because it isn’t. In the end I went with a different solution, a lot more complex then this one, but one that is clean and will remain very effective through the rest of the development of the Game: I wrote a DSL that both generates Property Lists and C# code to fully define, and in some cases handle some logic, a game level.

Extending EF 4.x DbContext Generator to support Hashcode and Equality comparers

Currently I’m trying to fix a bunch of errors on a deep cloning template for EF 4.1 dbContext generated objects. This is done on a live database model, that’s fairly complex. One of the issues I had was the algorithm reaching a relation that it wasn’t supposed to be cloned, but later on, founding another relation where the same set of entities was supposed to be cloned, so I was left with relationships with the original entities that should be updated to the new cloned ones.

To fix this I had to keep track of what’s being cloned, so that in the end, I can run a “fixup” pass and update anything that’s referencing original entities that ended up being cloned later on. I came up with 2 ways to do this, either extend the objects and keep track of cloning information on a per object basis, or just track everything with a set of dictionaries during the process. Because many people in the team also work with these objects, and we have a junior guy, I didn’t want to pollute the objects with stuff that’s not business related, so I went with the dictionary approach.

The goal of this post isn’t to explain in detail how the template works, instead I just explain how to extend it. It contains my own flavor of code generation template syntax, that wasn’t born with T4, but with codesmith generation tools, and there I picked up a lot of habits that I still retain.

For the objects to be “Dictionary Ready” I implemented IEquatable, overrode GetHashCode() and Equals(object obj).

1.Getting a list of all the Primary Key properties in the entity

A good rule of thumb in all generation templates is to isolate all the different things you will work with in lists. The current template already isolates 3 things:

  • propertiesWithDefaultValues
  • collectionNavigationProperties
  • complexProperties
var propertiesWithDefaultValues = entity.Properties.Where(p => p.TypeUsage.EdmType is PrimitiveType && p.DeclaringType == entity && p.DefaultValue != null);
var collectionNavigationProperties = entity.NavigationProperties.Where(np => np.DeclaringType == entity && np.ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.Many);
var complexProperties = entity.Properties.Where(p => p.TypeUsage.EdmType is ComplexType && p.DeclaringType == entity);

However we need a 4th IEnumerable containing all the primary keys for the entity, so we need to extend the previous code with:

var keyProperties = entity.Properties.Where(p => p.TypeUsage.EdmType is PrimitiveType && p.DeclaringType == entity && ef.IsKey(p));
var propertiesWithDefaultValues = entity.Properties.Where(p => p.TypeUsage.EdmType is PrimitiveType && p.DeclaringType == entity && p.DefaultValue != null);
var collectionNavigationProperties = entity.NavigationProperties.Where(np => np.DeclaringType == entity && np.ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.Many);
var complexProperties = entity.Properties.Where(p => p.TypeUsage.EdmType is ComplexType && p.DeclaringType == entity);

2.Implementing IEquatable on the class header

Next the class header needs to be slightly changed to implement the IEquatable interface, but still retain the base class option from EF.

I replaced:

<#=Accessibility.ForType(entity)#> <#=code.SpaceAfter(code.AbstractOption(entity))#>partial class <#=code.Escape(entity)#><#=code.StringBefore(" : ", code.Escape(entity.BaseType))#>

With:

<#=Accessibility.ForType(entity)#> <#=code.SpaceAfter(code.AbstractOption(entity))#>partial class <#=code.Escape(entity)#><# if(entity.BaseType == null) { #> : IEquatable<<#=code.Escape(entity)#>><# } else { #> : <#=code.Escape(entity.BaseType)#>, IEquatable<<#=code.Escape(entity)#>><# } #>

3. Implementing IEquatable on the class body

At the end of the class, insert the implementation of Equals(EntityName other):

    public bool Equals(<#=code.Escape(entity)#> other)
    {
        if(other == null) return false;
        var result = true;
<#
	foreach(EdmProperty key in keyProperties)
	{
#>
        if(<#=code.Escape(key)#> != other.<#=code.Escape(key)#>) result = false;
<#
	}
#>
        return result;
    }

4.Overriding GetHashCode() and Equals(object)

For the finishing part, I overrode GetHashCode and Equals, also at the end of the class, with:

    public override int GetHashCode()
    {
        unchecked
        {
            int hash = 17;
<#
	foreach(EdmProperty key in keyProperties)
	{
#>
            hash = hash * 23 + <#=code.Escape(key)#>.GetHashCode();
<#
	}
#>
            return hash;
        }
    }

    public override bool Equals(object obj)
    {
        return Equals(obj as <#=code.Escape(entity)#>);
    }

The GetHashCode implementation is a bit specific as it requires support for multiple keys. It is pulled from Joshua Bloch’s Effective Java. It is translated to C# and explained very well by Jon Skeet on Stackoverflow.