Click here to Skip to main content
13,592,944 members
Click here to Skip to main content
Add your own
alternative version


45 bookmarked
Posted 22 Oct 2011
Licenced CPOL

Custom Assembly Versioning with VS 2010 and MSBUILD Tasks

, 22 Oct 2011
Rate this:
Please Sign up or sign in to vote.
Auto incrementing and custom versioning of assemblies with Visual Studio 2010 and MSBUILD using MSBUILD Tasks


Introduction and Background

There is a plethora of resources that deal with auto incrementing build numbers and a wealth of plugins and other gizmos that manage assembly versioning. So why yet another article. The truth is that none of those options solved my problem. I needed something simple, easy to maintain and most importantly flexible with a local .NET flavour. So, naturally, I had to write my own humble solution.

One of the daunting tasks we often face when deploying assemblies is managing assembly and product versions. In any “decent” .NET solution, there is a need to auto-increment the version with every successful build. For example, incrementing the build part of the assembly version in this default scheme:


Sometimes, versioning requirements are more elaborate and demanding, we might want to append the build date as well as incrementing the build number, the version scheme might look like:


For that purpose, I prefer using the AssemblyFileVersion instead of the AssemblyVersion. The former has an open format and can accommodate virtually any additional information, whereas the latter, AssmeblyVersion is intended for use by the .NET framework and enforces a strict numbering scheme that yields compiler errors if infracted.

[assembly: AssemblyVersion("4.0.*")] //Strict Format, for framework use
[assembly: AssemblyFileVersion("")] 	//Flexible Format more suitable 
						//for product versions

This article describes how to leverage MSBUILD to automate this process and include it in the continuous integration pipeline.

Tips for Managing Multiple assembly.cs Files

In a solution with multiple projects and corresponding multiple assembly.cs files where AssemblyVersion and AssemblyFileVersion are kept, it is better to have one such file shared amongst all assemblies. To achieve this, we use a very useful visual studio feature which is Adding Existing Items as Links.


We use this technique to create one assembly information file to be shared amongst all the projects in the solution. This shared file will contain the AssemblyVersion and AssemblyFileVersion assembly attributes as well as any solution wide values, whereas the individual project level assembly.cs will contain project specific information such as:

using System.Reflection;
using System.Runtime.InteropServices;
[assembly: AssemblyTitle("POC.AssemblyVersioning.Common")]
[assembly: AssemblyCulture("")]
[assembly: Guid("bdf2e8b4-41aa-4569-b093-987439090dea")]

And here is how the solution structure will look like with the proposed scheme implemented... all for the sole purpose of facilitating modifying assembly version automatically.


And now to the more interesting part.

Building Custom MSBUILD Tasks

The reason why I prefer to use custom tasks in build automation as opposed to other scripting solutions is the glaring fact that Build Tasks are plain C# classes, where you can use the goodies that the .NET framework offers. To create a Build Task, all you have to do is:

  • Add references to the required .NET assemblies
  • references.png

  • Create a class that extends Microsoft.Build.Utilities.Task:

    public class MyTask : Task
        // The only behaviour that need be overridden
        public override bool Execute()
            throw new NotImplementedException();
  • Add a reference to the custom task inside a msbuild compliant file. Any XML file that references the following namespace is a valid msbuild file. Here is a sample file that references a custom task:

    <?xml version="1.0" encoding="utf-8" ?>
    <Project ToolsVersion="4.0" DefaultTargets="IncrementBuild" 
      <UsingTask AssemblyFile="bin\debug\POC.AssemblyVersioning.BuildTask.dll" 
    	TaskName="AutoIncrementTask" />
        <Target Name="IncrementBuild">
        <AutoIncrementTask AssemblyInfoPath="..\SharedAssemblyInfo.cs" />

And to simply invoke this task from a command line, we use this familiar syntax, assuming that the msbuild file was saved as sample.proj.

msbuild sample.proj /t:AutoIncrement 

Putting It All Together!

After having acquainted ourselves with MSBUILD tasks and thought about having one shared assembly file info that hosts the AssemblyVersion and AssemblyFileVersion attributes, I introduce here a simple way to go about updating those attributes through this simple custom task.

The task is based on file I/O where the contents of the shared assembly info will be parsed, the attributes updated and incremented (or transformed to the desired format) and the content re-written back to the file.

Here is the source code for the simple build tasks that will perform the file manipulation. This is for illustration purposes and intended only as a guide to creating your own build task.

I encourage you to.

public class AutoIncrementTask : Task
    private const string VersionPattern = 
	@"\[assembly: AssemblyFileVersion\(\""(\d{1}).(\d{1}).(\d{1,}).(\d{6})""\)\]";
    public string AssemblyInfoPath { get; set; }
    public override bool Execute()
            if (String.IsNullOrEmpty(AssemblyInfoPath))
                throw new ArgumentException("AssemblyInfoPath must have a value");

            string[] content = File.ReadAllLines(AssemblyInfoPath, Encoding.Default);
            var rx = new Regex(VersionPattern);

            var newContent = new List<string>();
            content.ToList().ForEach(line =>
                                                if (rx.IsMatch(line))
                                                    line = VersionMatcher(rx.Match(line));

            File.WriteAllLines(AssemblyInfoPath, newContent);

        catch(Exception ex)
            return false;

        return true;

    private string VersionMatcher(Match match)
        int major = int.Parse(match.Groups[1].Value);
        int minor = int.Parse(match.Groups[2].Value);
        int build = int.Parse(match.Groups[3].Value);
        string revision = match.Groups[4].Value;

        Console.WriteLine("AutoIncrement Assembly {0}", 
        Console.WriteLine("Current matched version: {0}.{1}.{2}.{3}", 
			major, minor, build, revision);

        revision = String.Format("{0}{1:d2}{2:d2}", 
        Console.WriteLine("Incremented to version: {0}.{1}.{2}.{3}", 
			major, minor, build, revision);

        string result = match.Result
			("[assembly: AssemblyFileVersion(\"$1.$2.{0}.{1}\")]");
        return String.Format(result, build, revision);

And here is the corresponding XML MSBUILD file:

<?xml version="1.0" encoding="utf-8" ?>
<Project ToolsVersion="4.0" DefaultTargets="IncrementBuild" 

  <UsingTask AssemblyFile="PATH_TO_TASK_DLL" TaskName="AutoIncrementTask" />
  <Target Name="IncrementBuild">
    <AutoIncrementTask AssemblyInfoPath="..\SharedAssemblyInfo.cs" />

As you can see, I chose the AssemblyFileVersion as the target for custom product and assembly versioning because there are no compile time checks on the format of the version and because a product version is more end-user and business-stakeholder friendly than the automatic build numbers used internally by the .NET framework.

You can include the previous build task as a step in the build process capitalizing on the MSBUILD command line capabilities.

Sample Code

I include a sample Visual Studio 2010 solution (.NET 4.0) that contains the code for the custom build task, and dummy projects to demonstrate the solution structure when implementing the shared assembly file:


  • Aug 7th, 2011, Originally published on my blog C# | B# | Stay#
  • Oct 22nd, 2011, Revised for CodeProject


This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


About the Author

Anas Karkoukli
Canada Canada

Blog: C# | B# | Stay#

You may also be interested in...

Comments and Discussions

GeneralMy vote of 5 Pin
Valery Possoz23-Jan-14 0:58
professionalValery Possoz23-Jan-14 0:58 
GeneralMy vote of 5 Pin
Dan_Barack15-Oct-12 3:31
memberDan_Barack15-Oct-12 3:31 
GeneralMy vote of 5 Pin
Vincent196814-Feb-12 3:02
memberVincent196814-Feb-12 3:02 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Cookies | Terms of Use | Mobile
Web01-2016 | 2.8.180618.1 | Last Updated 23 Oct 2011
Article Copyright 2011 by Anas Karkoukli
Everything else Copyright © CodeProject, 1999-2018
Layout: fixed | fluid