Thursday, September 17, 2009

Assembly version, File version, Product version

If you are a .NET developer, Assembly and File version would be familiar to you. They can be set in the Designer UI (project Properties page, Application tab, Assembly Information button...) which basically updates appropriate attributes in AssemblyInfo.cs.

Now, there is a less well known number - the Product version. It is not well documented and most developers ignore it altogether with no side-effects most of the time. However, it is an important number and it seems that, of the three, Product version is the most widely used.

The three version numbers simply take the values you give them or:

a. If Assembly version is not explictly specified, it takes the value of
b. If File version is not explicitly specified, it takes the value of Assembly version.
c. If Product version is not explicitly specified, it takes the value of File version.

In Windows Explorer of Windows XP and Server 2003, you can see from the properties of a file all three version numbers. In Windows Vista and later, you can't see Assembly version anymore.

To see the assembly version of a file in Vista or later without writing a program, simply type the following in Windows PowerShell:


Where xxxx.dll is the full path of your assembly

There are two special folders that developers should use for storing application level data and user level data respectively. They are:

a. Application.CommonAppDataPath
b. Application.LocalUserAppDataPath

To prevent applications from breaking and to keep good security hygiene, developers should always reference these two Application properties instead of hard-coding. Where the physical locations of these two folders are depend on whether you are using Server 2003 and earlier or Vista and later.

In Windows Server 2003 and earlier, Application.CommonAppDataPath is, in an unadulterated system, "C:\Documents and Settings\All Users\Application Data\CCCC\PPPP\vvvv" and Application.LocalUserAppDataPath is "C:\Documents and Settings\UUUU\Local Settings\Application Data\CCCC\PPPP\vvvv" for a non-roaming profile, where

a. UUUU is the "user id", loosely speaking.
b. CCCC is the Company name specified in the assembly.
c. PPPP is the Product name specified in the assembly.
d. vvvv is the four part Product version number. vvvv is not the File version number. Because Product version number has largely been ignored and adopts the File version number automatically, many may be led to think that vvvv is the File version number.

In Vista and later, CommonAppDataPath is by default "C:\ProgramData\CCCC\PPPP\vvvv" and LocalUserAppDataPath is "C:\Users\UUUU\AppData\Local\CCCC\PPPP\vvvv".

Why I came about to writing this article is because one day I decided to follow the good reasons given in KB 556041 to freeze the Assembly version temporarily and auto-increment the File version instead.

However, specifying something like "1.1.*" for File version in Visual Studio 2008 simply does not work. Somewhere in the assembly the File version is kept as "1.1.*" literally!

FileVersionInfo.GetVersionInfo(Assembly.GetExecutingAssembly().Location).FileVersion will return "1.1.*". That is alright in itself. But, if you don't explicitly specify the Product version, Product version will be equal to the File version and the asterisk character will cause your program to crash and burn when you try to access any of those two special folders mentioned above. The Windows file system does not accept "*" anywhere in a path name. The error is System.ArgumentException - "Illegal characters in path."

How do you specify the Product version? Simply put the following attribute in AssemblyInfo.cs:

[assembly: AssemblyInformationalVersion("v.R.b.r")]

To retrieve the various version numbers, use these:

string assemblyVersion = Assembly.GetExecutingAssembly().GetName().Version.ToString();
string assemblyVersion = Assembly.LoadFile('your assembly file').GetName().Version.ToString();
string fileVersion = FileVersionInfo.GetVersionInfo(Assembly.GetExecutingAssembly().Location).FileVersion;
string productVersion = FileVersionInfo.GetVersionInfo(Assembly.GetExecutingAssembly().Location).ProductVersion;

Hope the above information is useful to you.