Auto-generate fileversion for all projects in a solution with T4

When developing software you often have the need to centrally manage some assembly attributes like the file version for multiple Visual Studio projects at the same time.

The nice and easy approach I describe in this article allows you to do exactly that with almost no effort by utilizing the Text Template Transformation Toolkit (T4).

T4 is built into Visual Studio since version 2005 but in my opinion it is one of the best hidden gems in Visual Studio. It helps you to generate everything which can be saved as a text file (even .net classes!) and automate tasks in Visual Studio.

Read more about T4 on MSDN in the article Code Generation and T4 Text Templates and some introduction on Scott Hanselmanns blog (I know the article is from 2008, but it is still valid!)

Back to the problem

You have a Visual Studio solution with multiple projects. And even though it doesn’t have to do anything with it, we make them SharePoint projects for this example.
Why? Because almost any SharePoint project I see has AssemblyVersion and FileVersion set to 1.0.0.0 during the whole application lifecycle!

SharePoint projects have the problem that you often need to reference your assembly i.e. in ASPX pages.  So you would have to update all the references every time you update the assembly version. Otherwise your ASPX pages would break.

As many SharePoint developers seem not to know the difference between AssemblyVersion and FileVersion (or maybe just don’t care), they also leave the FileVersion property untouched, making it impossible to find out which version of the assembly is deployed on the farm.

The following approach creates new traceable fileversions on every build and applies them to all assemblies.

The ordinary way

Let’s have a look at a typical SharePoint solution (at least typical for me) in Visual Studio:

T4SolutionExplorer

As you can see, we have three SharePoint projects, a ClassLibrary and a deployment project (which has no assembly).

Each of the projects has its own AssemblyInfo.cs file which defines all the assembly properties like in this example:

The usual way would be to edit these properties in each AssemblyInfo.cs and update the AssemblyFileVersion everytime manually when a new release is built. Additionally you have make sure that everything stays in sync.

The better way

What we want to achieve is to maintain the common metadata in a separate class which is shared among all projects.
Additionally we want the fileversion to update automatically on each build.

To achieve that:

1. Create a new class library called “MetaData”

Note: In the example I choose to create a new MetaData project, but you could add the metadata file to any of the existing projects.

T4AddMetaDataProject

2. Create a new “Text Template” file called AssemblySharedInfo.tt

T4AddTTFile

The generated file will contain the following lines by default:

You see that the code looks a little bit like PHP markup.
The first line specifies which language this text template is using. In our case that is C#.
Next you see an assembly reference (similar to the references in a Visual Studio project).

You can also reference assembly dlls directly. Unfortunately this works only with a full file path which makes team development quite a hassle when the solution is checkedout from source control to different places.

The following three lines are typical imports of namespaces and the final line defines which file extension the generated file should have.

Checking the solution explorer, you see that the .tt file has a child item with the specified output extension. This file will be re-created every time the text template transformation is performed, i.e. when you save the template.

T4SolutionExplorer2

If you remove

the .tt file will default to create a .cs file in C# if you specified it as the templates language (and that is what we want right now).

3. Configure the template to transform on build (optional)

To make sure that we generate a new version on each build, we have to set the “Transform on Build” property to “True”

T4TemplateProperties

4. Add the shared assembly info metadata

Now we add the code of the AssemblyInfo which we want to share with all projects. For the template file this is not code which should be run, but just ordinary text. Therefore we do not have to encapsulate it in <# #> tags.

Just replace the existing content of the .tt file with the following. All the imports and references are not required for our example.

5. Add code to generate the file version

Now comes the interesting part!
A version number consists of the 4 parts major, minor, build number and revision and usually looks like that: 1.0.0.0
In my example I want to achieve the following:

  • the major version is defined manually,
  • the minor version is defined manually too,
  • the build number is the number of days which have passed since a certain date (i.e. the last public release date),
  • the revision number is a random number

The C# code for that would be:

You can adjust this code to your own preferences of course.

To integrate it into the template add the following code at the end of the .tt file

Notice that the C# code is embedded with <#+ #> in order to be executed by the template and the variables are referenced with <#= #>.  Also notice that the code which creates the variables is defined after the markup where they are used. T4 will build the code first and then render the markup, so we do not have a problem here.

As soon as you save the template the AssemblySharedInfo.cs file should contain something like that:

Neat, isn’t it?

6. Use the AssemblyShareInfo.cs in all projects

Now that we generated the file the way we want it to be, we have to integrate it in all our projects.
To do that, first of all we have to remove all the lines from the AssemblyInfo.cs which we have specified in the MetaData project.

Basically that will mean that only the following code remains in the file (with unique guids, titles and descriptions for each project)

Then you add an “Existing Item” to each project through the context menu

T4AddExistingItem

choose the generated AssemblySharedInfo.cs and add it as a link.

Note: This is the important part! If you do not add it as a link then a copy of the file is added, which will prevent it from being updated centrally.

T4AddExistingFile

Files added as a link will show a tiny overlay symbol

T4IconOverlay

7. Add a build dependency to the MetaData project

Finally we have to make sure, that the new file version is always generated before all other projects are built. To do that, edit the project dependencies of each project and make it dependent on the MetaData project.

T4ProjectDependencies

8. Build and forget :)

Now you can build your solution and verify that all your project assemblies have the same file version in Windows Explorer

T4FileVersionOverview

Conclusion

Providing an automatically updated file version for all assemblies is no big deal. You just have to configure it once and then Visual Studio will take care of the rest.
As you can imagine there are plenty of other ways you can use text templates to automate code generation.

To give you an example, the whole online documentation of the SharePoint Code Analysis Framework and the SharePoint Software Factory is automatically generated with T4, by reading the contents out of the Visual Studio project items.

  • Joe Loux

    Was there anything special you had to do to get the TransformOnBuild property to show up in the Properties panel for the T4 file? I’m on VS2012 and the option isn’t appearing. I’ve installed the Modeling SDK already. Thanks in advance.

  • Andy Three Saputra

    good and fantastic..

    i success following your code.
    but, how to get version number after generate by T4?
    i want version number that to placed view project.
    i call version number use :
    Version version = Assembly.GetExecutingAssembly().GetName().Version;
    ist return is 0.0.0.0 but in file AssemblySharedInfo.cs has changed : 1.0.1.21
    21 is autonumber.

    can you help me??