Ever since the release of .NET 1.1, there has existed an AssemblyVersionAttribute. This attribute determines the version number boiled into all .NET assemblies that is (supposed to) indicate something about when the assembly was built.
Whenever you create a new C# project in Visual Studio, it helpfully creates an “AssemblyInfo.cs” file (found in the project’s ‘Properties’ subfolder), that the new developer generally ignores (to their cost). This file is mostly auto-generated and manipulated from the project’s property pane.
For example, the above property pane from a blank console application leads to the following “AssemblyInfo.cs” file:
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyCopyright("Copyright © 2012")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
// The following GUID is for the ID of the typelib if this project is exposed to COM
// Version information for an assembly consists of the following four values:
// Major Version
// Minor Version
// Build Number
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
Unfortunately, the usefulness of the property pane means too many developers never get round to looking at this bit of code, or the helpful comments, which is why Visual Studio hides it away in the “Properties” subfolder in the first place.
The first thing to note is the funny syntax [assembly: AssemblyVersion("18.104.22.168")] . Actually, if you take a look at the MSDN attributes documentation, you will see that this is the full syntax for declaring an attribute – the bit before the : is actually the attribute target being set explicitly rather than being implied. This is particularly useful for assembly attributes – where there’s no code element to stick them next to. Actually, from the same documentation, you’ll notice some of the other elements that can be targeted with an attribute – but that’s another story that I might come back to in a later post.
So these are just normal attributes, targeted at an assembly itself. And there’s quite a few of them. As you can see from the above screenshot, it’s possible to edit them all using the “Assembly Information…” link on the first pane of the project’s properties panel. However, if you take the time to read the helpful comments in the source you can find some really useful information, and (importantly) you learn about the “1.0.*” assembly version trick.
When you specify version as “1.0.*” it get’s set automatically at build time to a new value which is based on the date and time of the build – which is exactly what we want! So what we need to do here is to change the last two lines to –
If you drop the AssemblyFileVersion attribute then the file version is set to being, the same as the assembly version (which is what you want in the majority of cases).
At this point, if you’re getting confused by AssemblyVersion in the code, but AssemblyVersionAttribute in the documentation, then don’t worry you can use either as the attribute name, but by convention (and for convenience) C# lets you drop the “Attribute” suffix from the attribute class name.
So what happens if we build our console application – well we get a nice executable file and if we browse to it and open up the file’s properties pane we can see the following on the details tab:
As you can see the File version and Product version (which is our “AssemblyVersion”) are both set to “1.0.4511.14207” and if we built it again – it changes:
Now it’s set to “1.0.4511.14356”. So clearly, this is a different version of the application. It’s probably worth pausing and pointing to the other useful information in the properties window, which also comes from the assembly attributes. If nothing else you now know why it’s worth spending the time setting all those values! (Though in the example above they’re all defaulted).
But what about those numbers, let’s be honest they’re hardly very useful, apart from indicating which build was newer (14356 is more than 14207). Well, in fact, going back to our friend MSDN, we discover that version 3 of the documentation for AssemblyVersionAttribute has the following useful nugget of information:
“When specifying a version, you have to at least specify major. If you specify major and minor, you can specify an asterisk (*) for the build. This will cause the build to be equal to the number of days since January 1, 2000, local time, and for revision to be equal to the number of seconds since midnight local time, divided by 2.”
So the “4511” in our example is the number of days since 1 January 2000, and the “14356” is the number of seconds since midnight, divided by 2. Great, has anyone got a calculator? Funny you should mention that –
After a lot of internal debate about using things like revision numbers from source control systems (which we did for a while) or using invalid version numbers like 1.0.20110508.75832 (each element is supposed to be a 32-bit integer), I threw together the above little utility to allow easy conversion between the default version number and the actual date and time. So from our original example, you can see the date was today (8 May 2012) and the time was 7:53AM (notice the last updated was 8:53AM because of daylight saving)
The second build was 5 minutes later.
So we can now get really useful information from builds – in fact, you can also drag assemblies straight onto the tool –
In the example above, you can see the debug and release assemblies were built at different times.
The other buttons allow useful stuff like auto-generation (to show the current date & time in version format) and copy to clipboard.
This tool is ‘commentware’ that is use it as much as you want but please leave me a comment !