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 0.0.0.0.
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:

[Reflection.AssemblyName]::GetAssemblyName('xxxx.dll').Version.

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.

6 comments:

Anonymous said...

Thanks! This helped me out!

alexandrul.ct said...

Thank you, just saved my day. In Windows Server 2008 I couldn't see the assembly version in dll properties, so I just set the product version to be the same as the assembly version.

George said...

Thank you for this discussion, but there is one thing still confusing me. What is the version number called that gets put into the Add/Remove Programs list? I set the AssemblyInformationalVersion to 5.4.3.2 in my AssemblyInfo.cs, and the Version number in the Product tag of my WiX Product.wks file to 2.0.0.0, and the Add/Remove Program line was "2.0.0.0".

How can I programatically access the "2.0.0.0" number?

S/360 said...

George, so it seems that Add/Remove programs show the Product version. If that is the version you want, see the almost last line of the blog above on how to retrieve it programmatically.

René said...

Thanks for the explanations. This means the easiest way to keep the visible versions in Vista/Server2008 current is to use these combination in AssemblyInfo.cs:

[assembly: AssemblyVersion("1.1.*")]
// [assembly: AssemblyFileVersion("0.0.0.0")]

Note: There is a star in AssemblyVersion and AssemblyFileVersion is commented out

S/360 said...

If you do this, your Product version will be incremented with every build!

Normally you would like to keep Production version relatively stable, as any user settings or data stored in CommonAppDataPath and LocalUserAppDataPath would be in a different folder everytime you introduce a new build.

For example if you keep a list of recent 10 files opened in LocalUserAppDataPath or say a registration key in CommonAppDataPath, then every time you distribute a new build, those information will be "lost" in another folder.