Creating MVC3 Razor views from a T4 Template

I blogged here about using T4 templates to inspect class properties. I also mentioned in passing that I had used it to create some MVC3 Razor views, so here is an example of that.

The process is essentially the same, except you need to change the output type from your template, like this:

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

To get it to work on a basic model class you'll need to add some extra references, to allow the compiler to do its thing. I've allowed for that by passing in an array of assembly file names. So you can do something like this:

Parser p = new Parser(file, "T4RazorView.Models.HomeModel");
p.AddReferences = getReferences();

...and implement a method which returns them, something like this:

string[] getReferences()
{
   return new[] {
      "C:\\Program Files (x86)\\Microsoft ASP.NET
      \\ASP.NET MVC 3\\Assemblies\\System.Web.Mvc.dll",
      "System.Web.dll",
      "System.ComponentModel.DataAnnotations.dll",
   };
}

Which is all there is to it. If you add extra properties to the Model, the Razor View will automatically update. So here's an example MVC3 project in Visual Studio 2010 if you're interested.

Inspecting Class Properties from a T4 Template

I wanted to write a T4 template to find all the properties inside one of my C# classes, which would allow me to auto-generate some code. After that, if I added another property the code should automatically update - and I would have one less thing to remember.

The solution I came up with involved using the C# compiler from inside the T4 template. The template actually builds an in-memory Assembly and then reflects over the compiled class to find it's properties. Then you can do whatever you like with them in the output. So here is an example project using that approach.

This means that you only need to do something like this:

<#
string path = this.Host.ResolvePath("");
string file1 = Path.Combine(path, "MyClass.cs");
string file2 = Path.Combine(path, "MyClass2.cs");
Parser p = new Parser(new string[] { file1, file2 }, "T4ClassProperties.MyClass");
p.WriteProperties(WriteLine, formatter);
#>

...and provide an extra function to format the output how you want it, like this:

<#+
string formatter(string s)
{
   return(string.Format("Console.WriteLine(\"- {0}\");",s));
}
#>

The example I've given makes a C# method that outputs the names of all the properties in a specified class to the console. But in reality I have used it to do things like build MVC3 razor views automatically.  To do that you'd just need to tell the template to output a .cshtml file instead.

The limitations are that the class file you are inspecting needs to compile stand-alone, or you need to be able to pass an array of source file names that will enable the class to build. You also have to specify any special assembly references, which I have not shown in this example, but is supported by my template. Also, to make it automatic, you need to get the T4 template to run as a part of the build process. So I've hacked the project file to run a "BeforeBuild" target in this example.

As you can see, all the magic happens inside ClassParse.tt, which you simply reference in your own template with something like:

<#@ include file="ClassParse.tt" #>

I thought that it might be worth blogging this, since it might come in handy again one day. I'm only looking at *properties* ... but it could be adapted to look at methods or anything else you can access via reflection...

[NOTE: if you'd like to know more about using T4 with MVC3, then you might to take a look here.]