Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C#

Walkthrough: How to increment AssemblyFileVersion automatically at each build using T4

4.96/5 (22 votes)
25 Sep 2013Ms-PL3 min read 96.3K   752  
Sometimes it could be useful to automatically increment the file version of an assembly at each build; this can be done even if you don't know MSBuild, using T4.

Introduction 

Sometimes it could be useful to automatically increment the file version of an assembly at each build; this can be done even if you don't know MSBuild, using T4.

Background

A T4 text template is a mixture of text blocks and control logic that can generate a text file. The control logic is written as fragments of program code in Visual C# or Visual Basic. The generated file can be text of any kind, such as a Web page, or a resource file, or program source code in any language. The T4 text templates can be translated by Visual Studio or by the TextTransform utility, TextTransform.exe. TextTransform.exe is a command-line tool that you can use to transform a text template. When you call TextTransform.exe, you specify the name of a text template file as an argument. TextTransform.exe calls the text transformation engine and processes the text template. So, using a simple T4 template, and running the transformation on the pre-build event, it is possible to autoincrement easily the Assembly File Version of one (or more) assemblies. This can be achieved by incrementing, for example, the revision number (the fourth from left, the 'X' in 1.0.0.X) each time the project is built.

Using the code

In order to achieve the automatic increment of the revision number:

  1. Right click on you csproj file, click on "Properties" on the context menu, click on the "Build Events" tab, then, add the following pre build action to the project: 
  2. First line:  

    set textTemplatingPath="%CommonProgramFiles(x86)%\Microsoft Shared\TextTemplating\$(VisualStudioVersion)\texttransform.exe"

    Second line:  

    if %textTemplatingPath%=="\Microsoft Shared\TextTemplating\$(VisualStudioVersion)\texttransform.exe" set textTemplatingPath="%CommonProgramFiles%\Microsoft Shared\TextTemplating\$(VisualStudioVersion)\texttransform.exe"

    Third line: 

    %textTemplatingPath% "$(ProjectDir)AssemblyFileVersion.tt" 

    The first two lines of code sets a custom environment variable, "%textTemplatingPath%", with the value of the "Common Files" folder that we need.  

    It is different on 32 bit machines and 64 bit machines. Using the MSBuild variable "$(VisualStudioVersion)" we make sure that the prebuild action we're writing will work on any VS version. The last line of code uses one environment variable, "%textTemplatingPath%", and another MSBuild variable, "$(ProjectDir)". Writing the path like this ensures that our solution is going to work with any version of Visual Studio
    on a 32 or a 64 bit machine.

    The first two lines of code sets a custom environment variable, "%textTemplatingPath%", with the value of the "Common Files" folder that we need. It is different on 32 bit machines and 64 bit machines. Using the MSBuild variable "$(VisualStudioVersion)" we make sure that the prebuild action we're writing will work on any VS version. The last line of code uses one environment variable, "%textTemplatingPath%", and another MSBuild variable, "$(ProjectDir)". Writing the path like this ensures that our solution is going to work with any version of Visual Studio on a 32 or a 64 bit machine.

    Image 1

  3. Remove the following line from the file AssemblyInfo.cs (usually located in the "Property" folder inside your C# project):
  4. [assembly: AssemblyFileVersion("1.0.0.0")]

    (Scroll down to the bottom in order to find it.)

    Image 2

  5. Add a new Text Template file "AssemblyFileVersion.tt" to the root folder of the project, copy inside of it the following t4 code, then you're done.
  6. C#
    <#@ template language="C#" hostSpecific="True"#>
    <#@ output extension="cs" #>
    <#@ import namespace="System.IO" #>
    <#
        int revisionNumber;
        try
        {
            //If we cannot find the file, the revision number is set to zero,
            //so even if the file doesn't exists the generation will run anyway.
            //NOTE: we suppose we're not messing with the generated file
            using(var f = File.OpenText(Host.ResolvePath("AssemblyFileVersion.cs")))
            {
                //We're reading the previous revision number; in order to make the
                //code as simple as we can, we're just going to rewrite it on the first row, commented.
                //This is not elegant, but it's simple enough and quite effective.
                string s = f.ReadLine().Replace("//","");
                revisionNumber = int.Parse(s) + 1; 
            }
        }catch
        {     
            revisionNumber = 0; 
        }
    #>
    //<#=revisionNumber#>
    // 
    // This code was generated by a tool. Any changes made manually will be lost
    // the next time this code is regenerated.
    // 
    
    using System.Reflection;
    
    [assembly: AssemblyFileVersion("1.0.0.<#= revisionNumber #>")]

    Image 3

    Image 4

    Image 5

  7. Now build the project. The generated "AssemblyFileVersion.cs" will be like the following:
  8. C#
    //0
    // 
    // This code was generated by a tool. Please do not change this document in any of its parts.
    // 
    
    using System.Reflection;
    
    [assembly: AssemblyFileVersion("1.0.0.0")]

Points of Interest

There are many other ways to achieve this result (Build server, MSBuild, ...), but I particularly like this one because this could be an easy way to get started with T4, even if you never used it. Of course the proposed solution can be easily improved. The good point of this solution is that the automatic increment mechanism can be easily spotted, understood and modified, by any developer of your team.

License

This article, along with any associated source code and files, is licensed under The Microsoft Public License (Ms-PL)