How to have an auto incrementing version number (Visual Studio)? [duplicate]
Asked Answered
G

9

544

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.

Grade answered 5/5, 2009 at 20:28 Comment(0)
S
700

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://mcmap.net/q/74686/-assemblyversion-using-fails-with-error-quot-wildcards-which-are-not-compatible-with-determinism-quot)

Surat answered 5/5, 2009 at 20:46 Comment(26)
It's also worth noting that if both AssemblyVersion and AssemblyFileVersion are specified, you won't see this on your .exeBunder
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 (unless you happen to be compiling code from inside your TARDIS -- in which case, can I come?).Pearse
Can we set at which value the * starts? Instead of using the number of days since year 2000?Desalinate
How should you get this change back into source control?Thereabout
Just commit it? Not sure I understand?Surat
try this System.Reflection.Assembly assembly = System.Reflection.Assembly.LoadFrom(Server.MapPath("bin/WidgetMaker.dll").ToString().Replace(@"Home\","")); Version ver = assembly.GetName().Version;Osteitis
BTW, you don't really have to edit and add in the assembly info file. A much easier way will be to go to project properties, application tab, click on "Assembly Information" and enter major version, minor version as you like and enter * in the third box and leave the 4th box blank. Visual studio will take care of update the .cs file with thisTevet
Note that in my project, AssemblyInfo.cs file was had been created by Visual Studio from the begining. So In such case, just modify existing file, not necessary to create it again.Imperialism
That's cool, but is there a way to report a SVN revision instead? Incrementing a number every day doesn't make much sense, because there could be plenty of changes for that day, so if someone testing the app at the same time, they end up with technically different versions which has the same version number.Evictee
Hi all, what's the implication over AssemblyFileVersion - should I take that out (as the system has already put it there)? Or also make it 1.0.*? Or something else?Newmann
In VS 2015 Express I get "Invalid version format" when I put a star in the 3rd field and press OKPruinose
Not sure if it's just me or VS2017, but adjusting AssemblyVersion to "X.Y.*" while leaving the AssemblyFileVersion with "X.Y.Z.W" resulted in weird behavior. Only after I have commented out the AssemblyFileVersion the "X.Y.*" started to behave as expected by defaulting build and revision numbers as explained above. I am not sure how they are related.Girlie
I cannot use wildcards in my .Net core project: "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"Gribble
I read your "since the year 2000" to mean "how many days we're beyond the year 2000". After all, 2nd Jan 2000 is not passed the year 2000. I would have instead said, "the build by default is the count of days since January 1st 2000".Dube
Using [assembly: AssemblyVersion("1.0.*")] and building at 5:36pm my resulting version is 1.0.6785.29889. 6785 is the correct number of days since Jan 1st 2000. If I divide 29889 by 2 (14,944) and then subtract that many seconds from 5:36pm the result is 1:26pm (not 12am). Even if GMT comes into play, I'm -4 hours GMT.Dube
This is a timestamp, not a version number. If you have builds in UAT and Release, UAT build with never released feature can in some scenarios have smaller version that the one in the release. Wrong.Thevenot
@DeveloperWebs Check the Microsoft codumentation posted in the answer. It states: The default revision number is the number of seconds since midnight local time (without taking into account time zone adjustments for daylight saving time), divided by 2.. So you have to multiply 29889 by two. You get 59778 seconds, which equals 4:36 PM. This doesn't takes into account the 1 hour of daylight saving time so it's perfectly correct.Carrousel
@Carrousel You misread what I said, or misunderstood it. The build number portion is to what I referred, NOT the revision number portion.Dube
@DeveloperWebs 6785 is the build number, and you said that it's correct. The revision number is 29889 and you said that this number is wrong, but you are dividing by two instead multiplying by two. You're substracting ~4 hours instead of ~16.6 hours, that's why you're getting 1:26PM and not 1:00AMCarrousel
@Carrousel I thought you meant the other post. 29889 * 2 would be 16.605 hours, or 4:36pm. Isn't that still off by one hour since I built at 5:36? The GMT would have been 9:36pm when I built.Dube
@DeveloperWebs it's off by one hour as stated by the Microsoft documentation: without taking into account time zone adjustments for daylight saving time. If you launch a build in winter time (from the 28th of October in Europe) the difference should be zero.Carrousel
@Carrousel So it's not local time (because local time DOES include daylight savings time), it's not GMT, and it's not an offset from GMT relative to actual local time. That's rather stupid isn't it?Dube
@DeveloperWeb Maybe they did it that way because on the night of the switch between the daylight saving time and the winter time you could have a revision number of a later build which is lower than a revision number of an earlier build, if you build around the moment when the switch happensCarrousel
But yeah, that's funny :-DCarrousel
I'd recommend keeping AssemblyVersion set to 0.0.*, and use Semantic Versioning for AssemblyFileVersion; e.g. 0.1.92. This way AssemblyVersion will automatically match whatever you set for AssemblyFileVersion, so you only have to maintain the one property.Wakerife
From @gideon answer below... If you put an asterisk in for build and revision visual studio uses: Build= number of days since Jan. 1st 2000, Rev= the number of seconds since midnight divided by 2. Therefore, subsequent visual studio "builds" on same day will be the same until the next day - so don't be fooled by that (it caught me a little off gaurd).Inweave
A
188

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.

  1. 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.

  1. 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.

Azov answered 5/5, 2009 at 20:28 Comment(13)
I think this is a great solution because it has the flexiblity of the addon-ons and custom executables, but is a pure out-of-the-box Visual Studio solution.Coldshoulder
Worked nicely for my needs, using bzr revno to populate part of the version infoKarakorum
This also works great for generating a build-specific cache busting token for JS and CSS references.Metic
I dont understand this solution... We have to call TransformText() method to get the result file...Ulotrichous
I agree with piedpiper. Is there a step missing? A c# file was created, but it looks nothing like what is shown above. There are 331 lines of code with a prominent function being: public virtual string TransformText()Timmerman
It looks to me like this only generates revision numbers that change on a daily basis. Doesn't sound very much to the point for me... I won't even be working on my project every day. And on the other hand, there will be days where I rework whole sections, worthy of minor and major updates. Did I miss something or is this just a "daily revision ticker"?Beside
@piedpiper @Timmerman Via Add New Item in the project's context menu, create Text Template, and not Runtime Text Template.Beckner
Also, these template are being rendered only if the template changes. This only works with AutoT4 Visual Studio Extension or something like that.Beckner
Using this solution, building from cmd with MSBuild doesn't increment versioning / run T4.Reina
I have created this How to Auto Increment Assembly or Assembly File Version, from MSBuild and appreciate any help.Reina
I just installed AutoT4 Visual studio extension but this answer doesnt work, what steps are missing ?.Sian
it doesnt update the AssemblyInfo.cs but it does update a CompiledVersion.txt (the tt file is named like that too but width .cs)Sian
I've been looking for a reason to try the T4 templates and add them to my skillset, and this answer is absolutely the gateway drug to get me started! Thank you, Dr. Matthieu-Frankenstein! Love, The MonsterDullish
V
65

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"
    
Vaughan answered 24/2, 2013 at 8:35 Comment(11)
Is it Possible to override the version number in few assemblies?Eric
@Tanya, Yes, just edit the AssemblyInfo.cs file manually before the build. Enter a number one less than what you want. So if you want 5, then enter 4.Vaughan
Instead of 10 you can reference the current Visual Studio version as a variable: "%CommonProgramFiles(x86)%\microsoft shared\TextTemplating\$(VisualStudioVersion)\TextTransform.exe" -a !!build!true "$(ProjectDir)Properties\AssemblyInfo.tt"Shanda
@BurnsBA, Thanks for the suggestion! I changed the answer to reflect that.Vaughan
Pre-build event are very important! Thank you! Once I did it, my version number become updating each time i build project from VS2017 or via console.Hippie
FYI if you are packaging this into a Nuget package, make sure and change the Build Action of the .tt file (properties) to None. That way when the end-user application utilizes your Nuget package, it doesn't inject your AssemblyInfo.tt file into their project.Castellanos
For 2017 community edition I've change the pre-build-event to: "c:\Program Files (x86)\Microsoft Visual Studio\2017\Community\Common7\IDE\TextTransform.exe" "$(ProjectDir)Properties\AssemblyInfo.tt" and it works fine for me. regardsPlourde
at least in VS 2017, you don't even need to set a manual pre-build command. It will be run automatically.Lone
"$(DevEnvDir)TextTransform.exe" can be used instead of "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\Common7\IDE\TextTransform.exe"Natator
@DrewChapin: How to pass more than one argument to the TextTransform.exe using the "a" option?Animalist
This is a good solution, however you have have the build and revision locations messed up. VS specifically says: Major.Minor.Build.Revision so you have to swap Revision and Build in your template. 1. new Regex("AssemblyVersion\(\"(?<major>\\d+)\\.(?<minor>\\d+)\\.(?<build>\\d+)\\.(?<revision>\\d+)\"\)"); 2. [assembly: AssemblyVersion("<#= this.major #>.<#= this.minor #>.<#= this.build #>.<#= this.revision #>")] 3. [assembly: AssemblyFileVersion("<#= this.major #>.<#= this.minor #>.<#= this.build #>.<#= this.revision #>")]Bedfast
S
32

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.

Satiable answered 9/9, 2010 at 15:38 Comment(2)
doesnt work at VS2013.Ulotrichous
thanks for the explanation - I was trying to figure out why Build number was not increasing (on same day) without looking at rev number. This explains it, thank you.Inweave
P
22

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

Periodical answered 5/5, 2009 at 20:53 Comment(4)
It increments randomly? Are they kidding me with this?Advertent
According to a comment left at msdn.microsoft.com/en-us/library/… the revision number isn't random, but instead it is the number of seconds since 12AM divided by 2, which in my opinion isn't so bad.Irrationality
There is SemVer standard. But Microsoft, as always, has its own rake.Stravinsky
The default revision number isn't random - in the link you provide it states 'The default revision number is the number of seconds since midnight local time (without taking into account time zone adjustments for daylight saving time), divided by 2.'Frasch
S
16

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.

Selfeffacing answered 5/5, 2009 at 20:39 Comment(0)
R
13
  • 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;
#>
Recipience answered 1/5, 2013 at 18:7 Comment(5)
I used this method but found that the copyright symbol changed to question mark when new assimblyinfo.cs was generated. Any ideas on how to fix it?Hart
@TheKing use a unicode code point instead of the literal character.Quorum
I don't get the + sign <#+ what is it for?Taxable
@Taxable I just changed a bit Drew Chapin's version https://mcmap.net/q/73528/-how-to-have-an-auto-incrementing-version-number-visual-studio-duplicate . So would be better to ask him.Recipience
Great stuff, just use this for the TextTransform.exe, it's much more succint: "$(DevEnvDir)TextTransform.exe"Silverplate
D
9

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

Decapitate answered 5/5, 2009 at 22:53 Comment(0)
V
2

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

Volding answered 23/12, 2009 at 19:12 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.