How to have an auto incrementing version number (Visual Studio)?

C#Visual StudioVersioning

C# Problem Overview


I want to store a set of integers that get auto incremented at build time:

int MajorVersion = 0;
int MinorVersion = 1;
int Revision = 92;

When I compile, it would auto-increment Revision. When I build the setup project, it would increment MinorVersion (I'm OK with doing this manually). MajorVersion would only be incremented manually.

Then I could display a version number in menu Help/About to the user as:

Version: 0.1.92

How can this be achieved?

This question asks not only how to have an auto-incrementing version number, but also how to use that in code which is a more complete answer than others.

C# Solutions


Solution 1 - C#

If you add an AssemblyInfo class to your project and amend the AssemblyVersion attribute to end with an asterisk, for example:

[assembly: AssemblyVersion("2.10.*")]

Visual studio will increment the final number for you according to these rules (thanks galets, I had that completely wrong!)

To reference this version in code, so you can display it to the user, you use reflection. For example,

Version version = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version;
DateTime buildDate = new DateTime(2000, 1, 1)
                        .AddDays(version.Build).AddSeconds(version.Revision * 2);
string displayableVersion = $"{version} ({buildDate})";

Three important gotchas that you should know

From @ashes999:
It's also worth noting that if both AssemblyVersion and AssemblyFileVersion are specified, you won't see this on your .exe.
From @BrainSlugs83:
Setting only the 4th number to be * can be bad, as the version won't always increment. The 3rd number is the number of days since the year 2000, and the 4th number is the number of seconds since midnight (divided by 2) [IT IS NOT RANDOM]. So if you built the solution late in a day one day, and early in a day the next day, the later build would have an earlier version number. I recommend always using X.Y.* instead of X.Y.Z.* because your version number will ALWAYS increase this way.

Newer versions of Visual Studio give this error:

> (this thread begun in 2009)

> The specified version string contains wildcards, which are not compatible with determinism. Either remove wildcards from the version string, or disable determinism for this compilation.

> See this SO answer which explains how to remove determinism (https://stackoverflow.com/a/58101474/1555612)

Solution 2 - C#

You could use the T4 templating mechanism in Visual Studio to generate the required source code from a simple text file :

> I wanted to configure version information generation for some .NET > projects. It’s been a long time since I investigated available > options, so I searched around hoping to find some simple way of doing > this. What I’ve found didn’t look very encouraging: people write > Visual Studio add-ins and custom MsBuild tasks just to obtain one > integer number (okay, maybe two). This felt overkill for a small > personal project. > > The inspiration came from one of the StackOverflow discussions where > somebody suggested that T4 templates could do the job. And of course > they can. The solution requires a minimal effort and no Visual Studio > or build process customization. Here what should be done: > > 1. Create a file with extension ".tt" and place there T4 template that will generate AssemblyVersion and AssemblyFileVersion attributes:

<#@ template language="C#" #>
// 
// 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: AssemblyVersion("1.0.1.<#= this.RevisionNumber #>")]
[assembly: AssemblyFileVersion("1.0.1.<#= this.RevisionNumber #>")]
<#+
    int RevisionNumber = (int)(DateTime.UtcNow - new DateTime(2010,1,1)).TotalDays;
#>

> > You will have to decide about version number generation algorithm. For > me it was sufficient to auto-generate a revision number that is set to > the number of days since January 1st, 2010. As you can see, the > version generation rule is written in plain C#, so you can easily > adjust it to your needs. > > 2. The file above should be placed in one of the projects. I created a new project with just this single file to make version management > technique clear. When I build this project (actually I don’t even need > to build it: saving the file is enough to trigger a Visual Studio > action), the following C# is generated: >

// 
// 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: AssemblyVersion("1.0.1.113")]
[assembly: AssemblyFileVersion("1.0.1.113")]

> Yes, today it’s 113 days since January 1st, 2010. Tomorrow the > revision number will change. > > 3. Next step is to remove AssemblyVersion and AssemblyFileVersion attributes from AssemblyInfo.cs files in all projects that should > share the same auto-generated version information. Instead choose “Add > existing item” for each projects, navigate to the folder with T4 > template file, select corresponding “.cs” file and add it as a link. > That will do! > > What I like about this approach is that it is lightweight (no custom > MsBuild tasks), and auto-generated version information is not added to > source control. And of course using C# for version generation > algorithm opens for algorithms of any complexity.

Solution 3 - C#

This is my implementation of the T4 suggestion... This will increment the build number every time you build the project regardless of the selected configuration (i.e. Debug|Release), and it will increment the revision number every time you do a Release build. You can continue to update the major and minor version numbers through Application ➤ Assembly Information...

To explain in more detail, this will read the existing AssemblyInfo.cs file, and use regex to find the AssemblyVersion information and then increment the revision and build numbers based on input from TextTransform.exe.

  1. Delete your existing AssemblyInfo.cs file.

  2. Create a AssemblyInfo.tt file in its place. Visual Studio should create AssemblyInfo.cs and group it with the T4 file after you save the T4 file.

    <#@ template debug="true" hostspecific="true" language="C#" #>
    <#@ output extension=".cs" #>
    <#@ import namespace="System.IO" #>
    <#@ import namespace="System.Text.RegularExpressions" #>
    <#
    	string output = File.ReadAllText(this.Host.ResolvePath("AssemblyInfo.cs"));
    	Regex pattern = new Regex("AssemblyVersion\\(\"(?<major>\\d+)\\.(?<minor>\\d+)\\.(?<revision>\\d+)\\.(?<build>\\d+)\"\\)");
    	MatchCollection matches = pattern.Matches(output);
    	if( matches.Count == 1 )
    	{
    		major = Convert.ToInt32(matches[0].Groups["major"].Value);
    		minor = Convert.ToInt32(matches[0].Groups["minor"].Value);
    		build = Convert.ToInt32(matches[0].Groups["build"].Value) + 1;
    		revision = Convert.ToInt32(matches[0].Groups["revision"].Value);
    		if( this.Host.ResolveParameterValue("-","-","BuildConfiguration") == "Release" )
    			revision++;
    	}
    #>
    
    using System.Reflection;
    using System.Runtime.CompilerServices;
    using System.Runtime.InteropServices;
    using System.Resources;
    
    // General Information
    [assembly: AssemblyTitle("Insert title here")]
    [assembly: AssemblyDescription("Insert description here")]
    [assembly: AssemblyConfiguration("")]
    [assembly: AssemblyCompany("Insert company here")]
    [assembly: AssemblyProduct("Insert product here")]
    [assembly: AssemblyCopyright("Insert copyright here")]
    [assembly: AssemblyTrademark("Insert trademark here")]
    [assembly: AssemblyCulture("")]
    
    // Version informationr(
    [assembly: AssemblyVersion("<#= this.major #>.<#= this.minor #>.<#= this.revision #>.<#= this.build #>")]
    [assembly: AssemblyFileVersion("<#= this.major #>.<#= this.minor #>.<#= this.revision #>.<#= this.build #>")]
    [assembly: NeutralResourcesLanguageAttribute( "en-US" )]
    
    <#+
    	int major = 1;
    	int minor = 0;
    	int revision = 0;
    	int build = 0;
    #>
    
  3. Add this to your pre-build event:

    "%CommonProgramFiles(x86)%\microsoft shared\TextTemplating\$(VisualStudioVersion)\TextTransform.exe" -a !!BuildConfiguration!$(Configuration) "$(ProjectDir)Properties\AssemblyInfo.tt"
    

Solution 4 - C#

If you put an asterisk in for build and revision visual studio uses the number of days since Jan. 1st 2000 as the build number, and the number of seconds since midnight divided by 2 as the revision.

A MUCH better life saver solution is http://autobuildversion.codeplex.com/

It works like a charm and it's VERY flexible.

Solution 5 - C#

Here's the quote on AssemblyInfo.cs from MSDN:

> You can specify all the values or you > can accept the default build number, > revision number, or both by using an > asterisk (). For example, > [assembly:AssemblyVersion("2.3.25.1")] > indicates 2 as the major version, 3 as > the minor version, 25 as the build > number, and 1 as the revision number. > A version number such as > [assembly:AssemblyVersion("1.2.")] > specifies 1 as the major version, 2 as > the minor version, and accepts the > default build and revision numbers. A > version number such as > [assembly:AssemblyVersion("1.2.15.*")] > specifies 1 as the major version, 2 as > the minor version, 15 as the build > number, and accepts the default > revision number. The default build > number increments daily. The default > revision number is random

This effectively says, if you put a 1.1.* into assembly info, only build number will autoincrement, and it will happen not after every build, but daily. Revision number will change every build, but randomly, rather than in an incrementing fashion.

This is probably enough for most use cases. If that's not what you're looking for, you're stuck with having to write a script which will autoincrement version # on pre-build step

Solution 6 - C#

Use AssemblyInfo.cs

Create the file in App_Code: and fill out the following or use Google for other attribute/property possibilities.

AssemblyInfo.cs

using System.Reflection;

[assembly: AssemblyDescription("Very useful stuff here.")]
[assembly: AssemblyCompany("companyname")]
[assembly: AssemblyCopyright("Copyright © me 2009")]
[assembly: AssemblyProduct("NeatProduct")]
[assembly: AssemblyVersion("1.1.*")]

AssemblyVersion being the part you are really after.

Then if you are working on a website, in any aspx page, or control, you can add in the <Page> tag, the following:

CompilerOptions="<folderpath>\App_Code\AssemblyInfo.cs"

(replacing folderpath with appropriate variable of course).

I don't believe you need to add compiler options in any manner for other classes; all the ones in the App_Code should receive the version information when they are compiled.

Hope that helps.

Solution 7 - C#

  • Star in version (like "2.10.3.*") - it is simple, but the numbers are too large

  • AutoBuildVersion - looks great but it doesn't work with my VS2010.

  • @DrewChapin's script works, but I can't set different modes for Debug pre-build event and Release pre-build event in my studio.

so I changed the script a bit... command:

"%CommonProgramFiles(x86)%\microsoft shared\TextTemplating\10.0\TextTransform.exe" -a !!$(ConfigurationName)!1 "$(ProjectDir)Properties\AssemblyInfo.tt"

and script (this works to the "Debug" and "Release" configurations):

<#@ template debug="true" hostspecific="true" language="C#" #>
<#@ output extension=".cs" #>
<#@ assembly name="System.Windows.Forms" #>
<#@ import namespace="System.IO" #>
<#@ import namespace="System.Text.RegularExpressions" #>
<#
    int incRevision = 1;
    int incBuild = 1;

    try { incRevision = Convert.ToInt32(this.Host.ResolveParameterValue("","","Debug"));} catch( Exception ) { incBuild=0; }
    try { incBuild = Convert.ToInt32(this.Host.ResolveParameterValue("","","Release")); } catch( Exception ) { incRevision=0; }
    try {
        string currentDirectory = Path.GetDirectoryName(Host.TemplateFile);
        string assemblyInfo = File.ReadAllText(Path.Combine(currentDirectory,"AssemblyInfo.cs"));
        Regex pattern = new Regex("AssemblyVersion\\(\"\\d+\\.\\d+\\.(?<revision>\\d+)\\.(?<build>\\d+)\"\\)");
        MatchCollection matches = pattern.Matches(assemblyInfo);
        revision = Convert.ToInt32(matches[0].Groups["revision"].Value) + incRevision;
        build = Convert.ToInt32(matches[0].Groups["build"].Value) + incBuild;
    }
    catch( Exception ) { }
#>
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("Game engine. Keys: F2 (Debug trace), F4 (Fullscreen), Shift+Arrows (Move view). ")]
[assembly: AssemblyProduct("Game engine")]
[assembly: AssemblyDescription("My engine for game")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyCopyright("Copyright © Name 2013")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]

// Setting ComVisible to false makes the types in this assembly not visible
// to COM components.  If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type. Only Windows
// assemblies support COM.
[assembly: ComVisible(false)]

// On Windows, the following GUID is for the ID of the typelib if this
// project is exposed to COM. On other platforms, it unique identifies the
// title storage container when deploying this assembly to the device.
[assembly: Guid("00000000-0000-0000-0000-000000000000")]

// Version information for an assembly consists of the following four values:
//
//      Major Version
//      Minor Version
//      Build Number
//      Revision
//
[assembly: AssemblyVersion("0.1.<#= this.revision #>.<#= this.build #>")]
[assembly: AssemblyFileVersion("0.1.<#= this.revision #>.<#= this.build #>")]

<#+
    int revision = 0;
    int build = 0;
#>

Solution 8 - C#

You could try using UpdateVersion by Matt Griffith. It's quite old now, but works well. To use it, you simply need to setup a pre-build event which points at your AssemblyInfo.cs file, and the application will update the version numbers accordingly, as per the command line arguments.

As the application is open-source, I've also created a version to increment the version number using the format (Major version).(Minor version).([year][dayofyear]).(increment). I've put the code for my modified version of the UpdateVersion application on GitHub: https://github.com/munr/UpdateVersion

Solution 9 - C#

You can do more advanced versioning using build scripts such as Build Versioning

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionesacView Question on Stackoverflow
Solution 1 - C#Noel KennedyView Answer on Stackoverflow
Solution 2 - C#Robert LewisView Answer on Stackoverflow
Solution 3 - C#Drew ChapinView Answer on Stackoverflow
Solution 4 - C#gideonView Answer on Stackoverflow
Solution 5 - C#galetsView Answer on Stackoverflow
Solution 6 - C#Micah SmithView Answer on Stackoverflow
Solution 7 - C#Dmi7ryView Answer on Stackoverflow
Solution 8 - C#MunView Answer on Stackoverflow
Solution 9 - C#RaymondView Answer on Stackoverflow