Versioning of .NET assemblies

I use four-parts version pattern that looks like: {Major}.{Minor}.{Date (MMdd)}.{Build Number}

An example version in this format would look like: 1.7.1028.37, which breaks down into being the first major release, seventh minor release, built on 28 October, and has been the 37th build for v1.7. Every time assembly is rebuild build counter increases.

version1

Sample solution is available for download here https://github.com/mchudinov/Versioning.

Version numbers in AssemblyInfo.cs file must be set before the assembly is build by continues integration system. Then an assembly will have exactly that version we need.

The meta information about a project including its version information is stored in AssemblyInfo.cs:

[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

.NET framework provides opportunity to set two different types of version numbers to each assembly. The difference between AssemblyVersion and AssemblyFileVersion is described in this article “How to use Assembly Version and Assembly File Version“. At least AssemblyVersion number must be used for versioning. Both version numbers will be useful for a framework assembly which is used by other developers and is build frequently. Then assembly file should be updated after each build but library functionality may stay unchanged.

To set the version numbers we can use MSBuild Extension Pack.

– Install MSBuild Extension pack NuGet package to the solution
Install-Package MSBuild.Extension.Pack

– Add project build file to the solution
If there is no MSBuild project file there yet add it. Let’s call this file Build.proj

– Add a target to the build file that will change version number
MSBuild Extension has a special set of targets to manipulate with assemblies info – AssemblyInfo. Here is a target that will set AssemblyVersion and AssemblyFileVersion according to the four-numbers pattern: {Major version}.{Minor version}.{Date (MMdd)}.{Build Number} for all AssemblyInfo.cs files in the project.

<UsingTask AssemblyFile="packages/MSBuild.Extension.Pack.1.5.0/tools/net40/MSBuild.ExtensionPack.dll" TaskName="AssemblyInfo"/>
<Target Name="Version">
	<Message Text="Versioning assemblies" />

	<ItemGroup>
	  <AssemblyInfoFiles Include="**\AssemblyInfo.cs" />
	</ItemGroup>

	<AssemblyInfo
		AssemblyInfoFiles="@(AssemblyInfoFiles)"
		
		AssemblyMajorVersion="$(MajorVersion)"
		AssemblyMinorVersion="$(MinorVersion)"
		AssemblyBuildNumberType="DateString"
		AssemblyBuildNumberFormat="MMdd"
		AssemblyRevisionType="AutoIncrement"
		AssemblyRevisionFormat="000"
	  
		AssemblyFileMajorVersion="$(MajorVersion)"
		AssemblyFileMinorVersion="$(MinorVersion)"
		AssemblyFileBuildNumberType="DateString"
		AssemblyFileBuildNumberFormat="MMdd"
		AssemblyFileRevisionType="AutoIncrement"
		AssemblyFileRevisionFormat="000"
	/>
</Target>

– Run this target before sources are compiled
Here is an example Buil.proj file that has 4 basic steps: clean solution, restore packages, then do versioning, and at last build application step. Script is compatible with both MSBuild and xbuild and can be build on Windows and Linux using both .NET and Mono. Read more about restoring packages and other build steps in my post about building and testing.

<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="Run">   
    <PropertyGroup>
        <Configuration>Release</Configuration>
        <SolutionName>Versioning</SolutionName>
    </PropertyGroup>

    <Target Name="Run">
     <CallTarget Targets="Clean" />
     <CallTarget Targets="Restore" />
     <CallTarget Targets="Version" />
     <CallTarget Targets="Build" />
    </Target>
    
    <Target Name="Clean">
     <Message Text="Clean" />
     <RemoveDir Directories="$(SolutionName)/bin;" ContinueOnError="False"/>
     <RemoveDir Directories="$(SolutionName)/obj;" ContinueOnError="False"/>
    </Target>
    
    <Target Name="Restore">
     <Message Text="Restore NuGet packages" />
     <Exec Command="nuget.exe restore" ContinueOnError="False"/>
    </Target>
  
    <UsingTask AssemblyFile="packages/MSBuild.Extension.Pack.1.5.0/tools/net40/MSBuild.ExtensionPack.dll" TaskName="AssemblyInfo"/>
    <Target Name="Version">
        <Message Text="Versioning assemblies" />
    
        <ItemGroup>
          <AssemblyInfoFiles Include="**\AssemblyInfo.cs" />
        </ItemGroup>
    
        <AssemblyInfo
            AssemblyInfoFiles="@(AssemblyInfoFiles)"
            
            AssemblyMajorVersion="$(MajorVersion)"
            AssemblyMinorVersion="$(MinorVersion)"
            AssemblyBuildNumberType="DateString"
            AssemblyBuildNumberFormat="MMdd"
            AssemblyRevisionType="AutoIncrement"
            AssemblyRevisionFormat="000"
          
            AssemblyFileMajorVersion="$(MajorVersion)"
            AssemblyFileMinorVersion="$(MinorVersion)"
            AssemblyFileBuildNumberType="DateString"
            AssemblyFileBuildNumberFormat="MMdd"
            AssemblyFileRevisionType="AutoIncrement"
            AssemblyFileRevisionFormat="000"
        />
    </Target>
  
    <Target Name="Build">
      <Message Text="Build $(Configuration)" />
      <MSBuild Projects="$(SolutionName)/$(SolutionName).csproj" Properties="Configuration=$(Configuration)" ContinueOnError="False"/>
    </Target>
</Project>

 

Let’s build the project. Note that on Windows MSBuild is not in PATH by default. Then to build application from command line a “Developer Command Prompt for VS2012” should be used.

C:\Program Files (x86)\Microsoft Visual Studio 11.0>msbuild d:\projects\C#\Mono\Versioning\Build.pro
j
Microsoft (R) Build Engine version 4.0.30319.18408
[Microsoft .NET Framework, version 4.0.30319.18444]
Copyright (C) Microsoft Corporation. All rights reserved.

Build started 05.11.2014 11:13:42.
Project "d:\projects\C#\Mono\Versioning\Build.proj" on node 1 (default targets).
Clean:
  Clean
  Removing directory "Versioning/bin".
  rd /s /q "Versioning/bin"
  Removing directory "Versioning/obj".
  rd /s /q "Versioning/obj"
Restore:
  Restore NuGet packages
  nuget.exe restore
  All packages listed in packages.config are already installed.
Version:
  Versioning assemblies
Build:
  Build Release
....
Done Building Project "d:\projects\C#\Mono\Versioning\Build.proj" (default targets).

Build succeeded.
    0 Warning(s)
    0 Error(s)

Time Elapsed 00:00:00.84

C:\Program Files (x86)\Microsoft Visual Studio 11.0>

After the build is complete version numbers AssemblyInfo.cs are changed

using System.Reflection;
using System.Runtime.CompilerServices;

[assembly: AssemblyTitle("VersioningPackaging")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("")]
[assembly: AssemblyCopyright("")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]

// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}".
// The form "{Major}.{Minor}.*" will automatically update the build and revision,
// and "{Major}.{Minor}.{Build}.*" will update just the revision.

[assembly: AssemblyVersion("1.0.1105.003")]
[assembly: AssemblyFileVersion("1.0.1105.003")]

Changes in AssemblyInfo.cs file should not be committed to CVS. Since these changes are normally done on CI-server it is not a problem.

Build binary has the right version number [assembly: AssemblyVersion("1.0.1105.003")]

versioning

External links about versioning: