Auto-increment build numbers in Visual Studio

You need to auto-increment your build numbers in order to easily tell which code you’re working with.

In this article I’ll explain how to auto-increment your build numbers in Visual Studio. I’ll be using text templating to generate the Assembly Version.

Update (2021-3-27): I added information about how to handle this .NET Core projects.

1 – Choose a versioning scheme

I’m going to be using the version scheme: <Major Version>.<Minor Version>.<Days Since Project Started>.<Minutes Since Midnight>. You should use whatever makes sense for you.

The one rule you must adhere to is the numbers must be <= 65534 (because they are 16-bit). If you generate a number greater than 65534, you’ll get a build error:

CS7034 The specified version string does not conform to the required format - major[.minor[.build[.revision]]]
Code language: plaintext (plaintext)

There are 86400 seconds per day and 1440 minutes per day. This is why I chose Minutes Since Midnight instead of Seconds Since Midnight. Since 86400 > the limit of 65534, using seconds would sometimes result in the build error shown above. By using minutes, this cannot happen.

2 – Comment out the assembly version properties

Open AssemblyInfo.cs and comment out AssemblyVersion and AssemblyFileVersion.

Note: This step doesn’t apply to .NET Core projects, unless you added an AssemblyInfo.cs file manually.

3 – Add a Text Template file

A Text Template is used to generate code. We’ll be using this to generate the assembly version.

After you add this file you’ll get a warning prompt. Since you’re the one adding this file, you can check the box and click OK.

4 – Update the Text Template to generate the AssemblyVersion property

There’s two parts to the text template:

  1. Specifying the template using placeholder variables.
  2. Populating the placeholder variables.
<#@ template debug="false" hostspecific="false" language="C#" #> <#@ output extension=".cs" #> using System.Reflection; [assembly: AssemblyVersion("<#= this.Major #>.<#= this.Minor #>.<#= this.DaysSinceProjectStarted #>.<#= this.MinutesSinceMidnight #>")] <#+ int Major = 1; int Minor = 0; static DateTime ProjectStartedDate = new DateTime(year: 2020, month: 3, day: 12); int DaysSinceProjectStarted = (int)((DateTime.UtcNow - ProjectStartedDate).TotalDays); int MinutesSinceMidnight = (int)DateTime.UtcNow.TimeOfDay.TotalMinutes; #>
Code language: C# (cs)

5 – Update .csproj to run the text template every time it builds

You have to add a few a few properties to the .csproj file to make it run the transform every time it builds. Check the appropriate section below based on if you’re using .NET Framework or .NET Core.

Updating the .csproj in a .NET Framework project

  1. Edit your .csproj in Notepad.
  2. Make two changes:
    • Import Microsoft.TextTempatings.targets.
    • Add the TransformOnBuild, OverwriteReadOnlyOutputFiles, and TransformOutOfDateOnly properties to each build configuration.

The .csproj below shows these highlighted changes:

<?xml version="1.0" encoding="utf-8"?> <Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <Import Project="$(MSBuildExtensionsPath)$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)$(MSBuildToolsVersion)\Microsoft.Common.props')" /> <PropertyGroup> <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> <ProjectGuid>{221097A0-A3F4-45CC-A6C0-B13455C6EAFE}</ProjectGuid> <OutputType>Library</OutputType> <AppDesignerFolder>Properties</AppDesignerFolder> <RootNamespace>AutoIncrementingBuild</RootNamespace> <AssemblyName>AutoIncrementingBuild</AssemblyName> <TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion> <FileAlignment>512</FileAlignment> <Deterministic>true</Deterministic> </PropertyGroup> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> <DebugSymbols>true</DebugSymbols> <DebugType>full</DebugType> <Optimize>false</Optimize> <OutputPath>bin\Debug\</OutputPath> <DefineConstants>DEBUG;TRACE</DefineConstants> <ErrorReport>prompt</ErrorReport> <WarningLevel>4</WarningLevel> <TransformOnBuild>true</TransformOnBuild> <OverwriteReadOnlyOutputFiles>true</OverwriteReadOnlyOutputFiles> <TransformOutOfDateOnly>false</TransformOutOfDateOnly> </PropertyGroup> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> <DebugType>pdbonly</DebugType> <Optimize>true</Optimize> <OutputPath>bin\Release\</OutputPath> <DefineConstants>TRACE</DefineConstants> <ErrorReport>prompt</ErrorReport> <WarningLevel>4</WarningLevel> <TransformOnBuild>true</TransformOnBuild> <OverwriteReadOnlyOutputFiles>true</OverwriteReadOnlyOutputFiles> <TransformOutOfDateOnly>false</TransformOutOfDateOnly> </PropertyGroup> <ItemGroup> <Reference Include="System" /> <Reference Include="System.Core" /> <Reference Include="System.Xml.Linq" /> <Reference Include="System.Data.DataSetExtensions" /> <Reference Include="Microsoft.CSharp" /> <Reference Include="System.Data" /> <Reference Include="System.Net.Http" /> <Reference Include="System.Xml" /> </ItemGroup> <ItemGroup> <Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="VersionAutoIncrement.cs"> <AutoGen>True</AutoGen> <DesignTime>True</DesignTime> <DependentUpon>VersionAutoIncrement.tt</DependentUpon> </Compile> </ItemGroup> <ItemGroup> <Content Include="VersionAutoIncrement.tt"> <Generator>TextTemplatingFileGenerator</Generator> <LastGenOutput>VersionAutoIncrement.cs</LastGenOutput> </Content> </ItemGroup> <ItemGroup> <Service Include="{508349B6-6B84-4DF5-91F0-309BEEBAD82D}" /> </ItemGroup> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v16.0\TextTemplating\Microsoft.TextTemplating.targets" /> </Project>
Code language: HTML, XML (xml)

Note: This is specifically adding the VS2019 path.

Updating the .csproj in a .NET Core project

  1. Click on the project so it opens the .csproj file for editing.
  2. Add the following properties
    1. Import Microsoft.TextTempatings.targets.
    2. Disable GenerateAssemblyInfo.
    3. Add the TransformOnBuild, OverwriteReadOnlyOutputFiles, and TransformOutOfDateOnly.
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <TargetFramework>netcoreapp3.1</TargetFramework> </PropertyGroup> <Import Project="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v16.0\TextTemplating\Microsoft.TextTemplating.targets" /> <PropertyGroup> <GenerateAssemblyInfo>false</GenerateAssemblyInfo> <TransformOnBuild>true</TransformOnBuild> <OverwriteReadOnlyOutputFiles>true</OverwriteReadOnlyOutputFiles> <TransformOutOfDateOnly>false</TransformOutOfDateOnly> </PropertyGroup> <ItemGroup> <None Include="VersionAutoIncrement.cs"> <DesignTime>True</DesignTime> <AutoGen>True</AutoGen> <DependentUpon>VersionAutoIncrement.tt</DependentUpon> </None> </ItemGroup> <ItemGroup> <None Update="VersionAutoIncrement.tt"> <Generator>TextTemplatingFileGenerator</Generator> <LastGenOutput>VersionAutoIncrement.cs</LastGenOutput> </None> </ItemGroup> <ItemGroup> <Service Include="{508349b6-6b84-4df5-91f0-309beebad82d}" /> </ItemGroup> </Project>
Code language: HTML, XML (xml)

If you don’t disable GenerateAssemblyInfo, then you’ll get a compile time error saying there’s a duplicate AssemblyVersion.

Note: This is specifically adding the VS2019 path.

6 – Build the project

When you build the project it’ll execute the text template. This generates a source file with the AssemblyVersion property.

10 thoughts on “Auto-increment build numbers in Visual Studio”

  1. To me, this is totally not working!
    Yes, the VersionAutoIncrementer.cs file is created, but it is stuck in its original version number.
    E.g. stuck in:

    using System.Reflection;
    [assembly: AssemblyVersion(“8.0.220.927”)]

    Reply
    • Hi Bjorn,

      Good catch. I updated the page to include instructions for how to update your .csproj file to make it run the text templating transform on every build.

      Please take a look at the step I added to the page – 5 – Update .csproj to run the text template every time it builds.

      Let me know if this helps.

      Reply
  2. I have created the template for shared assembly info.tt its updating version number only once for the first build or rebuild.
    If I change some code and try to build the whole project it’s not reflecting the version number.

    Reply
      • Hi Mak,
        Yes, I did. if I do changes related to that project then the revision number getting updated.if anything other than that project it’s not updating.

        Below is my code in SharedAssembyInfo.tt

        using System.Reflection;

        [assembly: AssemblyConfiguration(“”)]
        [assembly: AssemblyCompany(“GRIDSMART Technologies, Inc.”)]
        [assembly: AssemblyCopyright(“Copyright © GTI 2019”)]
        [assembly: AssemblyTrademark(“”)]
        [assembly: AssemblyCulture(“”)]
        [assembly: AssemblyVersion(“…”)]

        And followed all the steps included the below line in .csproj

        Reply
        • The text template only runs if the project is built. If there’s no changes in the project, then clicking “Build” in Visual Studio won’t build that project. Therefore it won’t run the text template.

          I’m not aware of a way to make “Build” build all projects, even if there are no changes.

          However, since it sounds like you want to run the text template every time, regardless of changes to the project, it really sounds like you want to use “Rebuild” instead of “Build” every time. That’s the simplest solution. There may be other ways to force VS to build your unchanged project, but “Rebuild” definitely makes it do that.

          Reply
    • Hi Chris,

      That’s unusual that the Text Template is missing. What version of Visual Studio are you using? Which .NET version? and which language (C# or VB)?

      Do you have the Text Template Transformation component installed?

      Update (2021-3-27): I just ran into this when using a specific project type. You can just add the Text File, change the extension to .tt, and paste in the text templating code (use the code shown in this article as a starting point). VS updates the .csproj the same way as if you had added a Text Template new item. I think this is a bug in VS, where it’s not showing the Text Template item as an option, even though it’s installed.

      Reply
    • Hi Sid,

      Thanks for your question. I realized I didn’t have a section showing how to update a .NET Core .csproj. So I just added this section: Updating the .csproj in a .NET Core project

      Regarding your question about Blazor .NET Core specifically, the instructions in the article (including the new .NET Core section) work fine. I just tried it out by creating a new Blazor app targeting .NET Core. I added the VersionAutoIncrement.tt and .csproj updates to all three projects (Shared/Client/Server). Then rebuilt the solution and it ran all the transforms and updated all of their assembly versions. Note: I haven’t used Blazor before, so I’m not sure if updating the version in all three projects would matter.

      A few things:
      1. When I tried to add a new Text Template in the Client/Server projects, “Text Template” was missing from this list. I just picked a Text File and changed the extension to .tt and put the text templating code (from this article) and it was fine. It must be a bug in VS causing it to not show Text Template in this list of new items.

      2. The text template runs for each project separately. In this article, it shows how to put the TotalMinutes as part of the version. This means if you are building multiple projects, it’s possible for the final assembly versions to be different between different assemblies built together.

      Please try it out and let me know how it goes.

      Reply

Leave a Comment