There are a lot of articles on the Internet about incrementing versions of their applications and each one uses its own method. Someone uses revisions as “builds”, someone has the number of seconds of the current day (for example, Microsoft), someone has something else.
My project uses 4 defining versions.
For example,
1.2.34.56 , where:
1 - Major version: Critical changes to the project (new functionality was introduced, existing ones were redesigned, etc.). Set manually;
2 - Minor version: Changing the functional parts of the application, a significant improvement in the code, etc. It is installed manually;
24 - Build: release number entering the community. Automatically assigned;
56 - Revision: revision number obtained with GIT. Assigned automatically.
')
I will not consider who uses what methods, so I will write how I achieved this result.
Step 1. Preparation
First we need to go to the project settings (
Project ->
MyProject Properties ). Here, in the
Application tab, go to the
Assembly Information and check that all 4 fields of the
Assembly version parameter are filled, and the first 2 digits indicate the corresponding to our release. In my case, this is version "
2.3 ", and the remaining numbers are set to any.

After making changes, we need to go to the project folder and find the
AssemblyInfo.cs file, which is usually located in the
Properties folder.
We open the file for editing and at the very bottom look for the lines:
Delete the commented line:
This is necessary for the reason that when writing a new version a regular expression will be used that reads the key digits of the version (major, minor) from the first match found.
Removed, saved, closed the file. More we do not need it.
Step 2. “ChangeRevision”
For convenience, I compiled a console application that reads the major, minor, and build values ​​from the
Properties \ AssemblyInfo.cs file, as well as the
number of GIT commits .
So, the code
ChangeRevision.exe :
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; using System.IO; using System.Diagnostics; namespace ChangeRevision { class Program { static void Main(string[] args) { try { Process process = new Process(); process.StartInfo.WorkingDirectory = Environment.CurrentDirectory; process.StartInfo.FileName = "\"c:\\Program Files (x86)\\Git\\cmd\\git.exe\""; process.StartInfo.Arguments = @"rev-list master --count"; process.StartInfo.UseShellExecute = false; process.StartInfo.RedirectStandardOutput = true; process.StartInfo.RedirectStandardError = true; StringBuilder output = new StringBuilder(); int timeout = 10000; using (AutoResetEvent outputWaitHandle = new AutoResetEvent(false)) using (AutoResetEvent errorWaitHandle = new AutoResetEvent(false)) { process.OutputDataReceived += (sender, e) => { if (e.Data == null) outputWaitHandle.Set(); else output.AppendLine(e.Data); }; process.Start(); process.BeginOutputReadLine(); if (process.WaitForExit(timeout) && outputWaitHandle.WaitOne(timeout)) { string text = File.ReadAllText(@"..\..\..\"+args[1]+@"\Properties\AssemblyInfo.cs"); Match match = new Regex("AssemblyVersion\\(\"(.*?)\"\\)").Match(text); Version ver = new Version(match.Groups[1].Value); int build = args[0] == "Release" ? ver.Build + 1 : ver.Build; Version newVer = new Version(ver.Major, ver.Minor, build, Convert.ToInt16(output.ToString().Trim())); text = Regex.Replace(text, @"AssemblyVersion\((.*?)\)", "AssemblyVersion(\"" + newVer.ToString() + "\")"); text = Regex.Replace(text, @"AssemblyFileVersionAttribute\((.*?)\)", "AssemblyFileVersionAttribute(\"" + newVer.ToString() + "\")"); text = Regex.Replace(text, @"AssemblyFileVersion\((.*?)\)", "AssemblyFileVersion(\"" + newVer.ToString() + "\")"); File.WriteAllText(@"..\..\..\" + args[1] + @"\Properties\AssemblyInfo.cs", text); } } } catch (Exception ex) { Console.WriteLine(ex.Message); Console.WriteLine(""); Console.WriteLine(ex.StackTrace); Console.ReadLine(); } } } }
We put the compiled file in the
Solution directory.
Below I will describe in more detail how this code works.
Step 3. Pre-Build Event
Since I need to change the build version before compiling, the code fits into the
Pre-Build Event window.
"$(SolutionDir)ChangeRevision.exe" $(ConfigurationName) "$(ProjectName)"

Where:
"$ (SolutionDir) ChangeRevision.exe" - Indicates the path to the solution indicating the launch of our compiled file, which is written above.
$ (ConfigurationName) -
Configuration type (
Debug or
Release ).
If the
Debug parameter was passed when the
ChangeRevision.exe file was launched, then in the project version
only the revision value will be
increased , that is, if it was 2.3.0.0, it will become 2.3.0.x, where "x" is the number of commits for the project. If the
Release parameter is passed, the
build number will be automatically incremented along with the change in revision by the number of commits . For example, it was 2.3.0.0, it becomes 2.3.1.x, where "x" is the number of commits for the project.
"$ (ProjectName)" - Project Name
UPD: The parameter containing the name of the project was deleted from the program code, because when the project was compiled, the starting directory for launching the file with the parameter was
$ (ProjectDir) \ bin \ Debug / Release , which resulted in an error. Thus, the transfer of the project name has disappeared as such, since the
ChangeRevision.exe application uses a transition to the upper level relative to the launch directory, that is, specifying the path
".. \ .. \ Properties \ AssemblyInfo.cs" the program goes to the project directory and from there to
“Properties” , where it finds the required
AssemblyInfo.cs file
"UPD 2: As practice has shown, if there are several projects in Solution and choosing not the default one for compilation, then the starting directory will be, for some reason, the default project directory. In general, the code is still a little refined and changed at the top, namely, the parameter to transfer the project name has been reintroduced, which is intercepted in
ChangeRevision.exe second in a row. Thus, the path to
AssemblyInfo.cs has been changed to:
@"..\..\..\" + args[1] + @"\Properties\AssemblyInfo.cs"
That is, when compiling any project, the start directory is shifted up 3 steps (the solution directory) and then moved to the project folder specified in the file launch parameter, moving to the desired file.
The number of commits can be obtained by passing the parameter
git rev-list master --count
This is if you need to get the number of commits from the
MASTER branch.
Upon completion of the application, the
Properties \ AssemblyInfo.cs file passed in the first parameter of the project will be modified, after which the development environment will compile the project file itself with the version specified in the file.
PS: If you change the version of
AssemblyVersion , the value in the
AssemblyFileVersion parameter and, in some cases, the
AssemblyFileVersionAttribute , also changes.
Thus, I achieved a semi-automatic incrementing version of my application.
PS: Of course, working in a team or performing regular version merging, this option is
not suitable AT ALL, as the number of commits can suddenly decrease, thus we get a “new” “old” version of software. And for one person, without the use of combining versions, this option is more than sufficient.
Thanks for attention!
UPD: Made changes to the code in Step 2. Corrected descriptionUPD 2: All at the same step again changes in the code.