A Guide to AssemblyVersion and FileVersion
The components of a Microsoft DLL or EXE version number are Major, Minor, Build, and Revision. According to Microsoft, the components are used by convention as follows:
Major: Assemblies with the same name but different major versions are not interchangeable. A higher version number might indicate a major rewrite of a product where backward compatibility cannot be assumed.
Minor: If the name and major version number on two assemblies are the same, but the minor version number is different, this indicates significant enhancement with the intention of backward compatibility. This higher minor version number might indicate a point release of a product or a fully backward-compatible new version of a product.
Build: A difference in build number represents a recompilation of the same source. Different build numbers might be used when the processor, platform, or compiler changes.
Revision: Assemblies with the same name, major, and minor version numbers but different revisions are intended to be fully interchangeable. A higher revision number might be used in a build that fixes a security hole in a previously released assembly.
Defining Version Numbers
In the real world, version numbers mean different things to different people. However, I tend to use Microsoft’s definition for Major and Minor when using Visual Studio and MSBuild. On the contrary, Visual Studio’s automatic assignment for Build and Revision defines Build as the number of days since January 1, 2000, and Revision as the number of seconds (divided by two) into the day on which the compilation was performed. The number of seconds must be divided by two since there are 86,400 seconds in a day, and the maximum value of the Revision number is 65534 (yes, not 65535, which causes an error).
Error generated by using 65535 as Build or Revision
A Personal Example
Recently I was told that an issue was found in a Windows service that I support, as of version 1.0.5876.25143. To find the changeset used to build that version, I only have timestamps to compare.
Changeset and Date, but no Version
Fortunately, in our AssemblyInfo.cs property file, we use the automatic version format, with an asterisk in the Build position.
[assembly: AssemblyVersion("1.0.*")]Code language: JSON / JSON with Comments (json)
The Build and Revision portions of the version are automatically set to the date and time as described above, so all I needed to do is convert the values.
- Build 5876 is 5876 days after January 1, 2000; in this case, February 2, 2016.
- Revision 25143 is one-half the number of seconds into the day; in this case 1:58:06 PM.
So I know that the changeset in question is 99119.
To make this easy to figure out, I wrote a simple console program to do the conversion. It simply takes a version number on the command line (with gross assumptions that it’s in the correct format), parses out the value using Version.Parse. It takes the Build number and adds that number of days to 1/1/2000, then adds twice the number of seconds as defined by the Revision number, and writes out the result as version elements and as a date and time.
C:\> VersionToDate 1.0.5876.25143 Major : 1 Minor : 0 Build : 5876 = 2/2/2016 Revision: 25143 = 1:58:06 PM
Here is the program source.
Besides setting the AssemblyVersion, I also remove the FileVersion setting. If FileVersion is specified, then its value is used as-is even when the AssemblyVersion is automatically assigned. Even though you’re setting the AssemblyVersion, if FileVersion remains 188.8.131.52, your DLL or EXE will appear to be version 184.108.40.206. By removing it, the FileVersion defaults to the AssemblyVersion. More so, FileVersion does not support automatic versioning so either fully hard-coded it or completely remove it, as I suggest here.
[assembly: AssemblyVersion("1.0.*")] //[assembly: AssemblyFileVersion("220.127.116.11")]Code language: JSON / JSON with Comments (json)
Let’s Take It a Step Further
Now that we know how to decipher the version number let’s look at making Assembly Versions a bit more useful. For instance, if your solution has several projects, you may want each DLL to have the same version so they can easily associate with each other. You could do it the hard way and make sure you keep all of your AssemblyVersions the same in every AssemblyInfo.cs file. Or you could use a single shared AssemblyInfo.cs file, so you only have to set one AssemblyVersion value.
To do this, copy or create an AssemblyInfo.cs file in the same folder as your solution file (or in Resources if you prefer). Create a Solution folder if you don’t already have one.
Drag the new AssemblyInfo.cs file onto your Solution folder.
Remove the AssemblyInfo.cs file from each of your projects, and for each one, right-click the project and select Add -> Existing Item.
Find the common AssemblyInfo.cs file and select it, but rather than clicking Add, click the arrow next to Add and select Add As Link.
The AssemblyInfo.cs file will drop into the project folder rather than into the Properties sub-folder. So just drag it onto Properties and you’re all set.
You will not see the AssemblyInfo.cs file in the Properties folder of your project. It only exists on disk in the one place you created it, which is why we keep a Solution Folder reference to it.
Now, whenever you change the version in the Solution copy of AssemblyInfo.cs (or any of the linked versions, for that matter) all projects will have the same change.
Alternatively, when a project that you want to use a unique version number for has most others shared, just keep an actual AssemblyInfo.cs file in that project instead of a link to the shared one. That project will retain its specific version independent of the shared version.
Check out my other blog When to Use and Not Use Variable Type var in C#!