A Guide to AssemblyVersion and FileVersion

Estimated reading time: 7 minutes

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.

Contents

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 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 65535

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 change set used to build that version, I only have timestamps to compare to.

changese and date

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.*")]

The Build and Revision portions of the version 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 change set 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.

class Program
{
    static void Main(string[] args)
    {
        if (args.Length == 0 || string.IsNullOrWhiteSpace( args[0] ))
        {
           Console.WriteLine( "Usage: VersionToDate Major.Minor.Release.Build");
           return;
        }

        var version = Version.Parse( args[0] );

        // Calculate assembly date
        var date = new DateTime(2000, 1, 1)     // baseline is 01/01/2000
            .AddDays(version.Build)             // build is number of days after baseline
            .AddSeconds(version.Revision*2);    // revision is half the number of seconds into the day

        Console.WriteLine("Major   : {0}", version.Major);
        Console.WriteLine("Minor   : {0}", version.Minor);
        Console.WriteLine("Build   : {0} = {1}", version.Build, date.ToShortDateString());
        Console.WriteLine("Revision: {0} = {1}", version.Revision, date.ToLongTimeString());
    }
}

Another Point

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 1.0.0.0, your DLL or EXE will appear to be version 1.0.0.0. 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("1.0.0.0")]

versiontodate details

VersionToDate Properties/Details

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.

solutionfolder

Drag the new AssemblyInfo.cs file onto your Solution folder.

Screen Shot 2016-03-15 at 12.21.19 PM

Remove the AssemblyInfo.cs file from each of your projects, and for each one, right-click the project and select Add -> Existing Item.

Screen Shot 2016-03-15 at 12.21.39 PM

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.

Screen Shot 2016-03-15 at 12.22.02 PM

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.

Screen Shot 2016-03-15 at 12.24.52 PM

Screen Shot 2016-03-15 at 12.25.01 PM

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 version, 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.

Want More?

Check out my other blog When to Use and Not Use Variable Type var in C#!

Leave a comment

Your email address will not be published. Required fields are marked *