Easy Release Versioning for .NET Projects using Azure DevOps and TFS

Published on
Reading time
Authors

Versioning. Here we are. Again.

Over the years I have always worked hard to make versioning a foundational piece of every CI / CD solution I've setup. Reliable, logical versioning becomes key to long-term maintenance and troubleshooting efforts, and whatever you can do to make it a "no-brainer" is worth it (your future self will thank you).

The move to .NET Core changed the way a few items work in the .Net world, including versioning, and besides, I am always looking for ways to make versioning easier.

So here's my cheat-sheet for versioning your solutions. It won't suit all application types, but for my use case (.NET Web Apps) it works just fine. It will work with Azure DevOps and newer TFS versions too.

I haven't tested on VB projects, but this should work for them just as easily as C#.

NET Core: Setup Your Project File

Versioning has been simplified in the .NET Core world. Edit your csproj and modify it as follows:

<PropertyGroup>
  <Version Condition=" '$(BUILD_BUILDNUMBER)' == '' ">1.0.0.0</Version>
  <Version Condition=" '$(BUILD_BUILDNUMBER)' != '' ">$(BUILD_BUILDNUMBER)</Version>
</PropertyGroup>

If your file doesn't have a version node, add the above. This tip comes from Stack Overflow, but I've modified it slightly.

The above setup will mean debugging locally will give you a version of 1.0.0.0, and in the event you build in a non-Azure DevOps / TFS environment you will also end up with a 1.0.0.0 version. $(BUILD_BUILDNUMBER) is an environment variable set by Team Build and which will be updated at build time by Azure DevOps or TFS.

NET Framework: Add Custom Task

In the "old" .NET world we have to update the properties of the AssemblyInfo file that is a part of the project, specifically targeting File Version and Assembly Version.

There isn't an in-built build Task to do this for you, and rather than hack together a script, why not use a great custom task from the marketplace (which also supports TFS)?

I'm using the "Assembly Info" task from Bleddyn Richards, primarily because it has the most recent updated date out of the similar tasks available, which means it's hopefully getting plenty of love and care from the owner 🙂.

Add the above Task to your build definition (make sure to do it before you build the Solution / project) and then set the version numbering as shown below.

Azure DevOps Task Config - versioning

Setup Build Versioning

The above steps are great, but they will count for nothing (or cause a compile fail) if we don't have a valid versioning number.

The default Azure DevOps build version number format takes this format:

$(date:yyyyMMdd)$(rev:.r)

This results in a build number that looks like this:

20180201.1 (for the first build on February 1 2018).

This isn't a valid .NET Version number, so we need to change it.

First, let's add two Variables to our build definition: MajorVersion and MinorVersion.

You can set these to any valid integer value. These can be manually controlled over time as you determine the need to increment Major and Minor version numbers. Note you can make them whatever you like, keeping in mind the size restriction I mention below.

Build Variables

Now let's change the Build Numbering scheme to use these variables, a specific date format, and the revision:

Number Format
$(MajorVersion).$(MinorVersion).$(date:yy)$(DayOfYear)$(rev:.r)

Which produces a build number that looks like this:

2.0.18037.1 (for first build on February 6 2018 for Major Version 2, Minor Version 0).

You can choose a format that works for you, with one proviso that each version segment must be less than 65,000, which sounds like a lot, until you consider that 20180201 (Feb 1, 2018) is, as an integer (20,180,201) larger than 65,000. Hence my decision to drop to using YY (if you're reading this in the year 2065 I apologise for my shortsightedness).

The result of these changes will mean that you'll have a lovely version number automatically written into your solution at build time. An example from a .NET Framework solution is shown below.

Properties Dialog

Happy Days 😎