As we are moving from prototype to product one of things we urgently need is the ability to track precisely which version of software was being used for any data processing run. In C++ we are on Linux so simply have the makefile generate a version.h header for every build. For C# the process was slightly more convoluted.

.NET has an AssemblyVersion and AssemblyFileVersion attribute for every .assembly These are usually defined in the AssemblyInfocs for a project I .wanted at least one of them to be dynamically updated by the build We have .TFS for source control so at least part of the version should be the TFS .revision I’m introducing Jenkins as a build/CI/test/etc system so the Jenkins .build should be another part (or 0 for builds not done on the server to .indicate they are unofficial)

This needs some MSBuild magic.

Most of the magic though is knowing to use the MSBuild Extension Pack. So first we include that in the relevant .csproj files.

<import project="$(MSBuildExtensionsPath)\ExtensionPack\4.0\MSBuild.ExtensionPack.tasks"></import>

Then at the end of the .csproj files we update the BeforeBuild target to trigger our version target:

<target name="BeforeBuild" dependsontargets="AssemblyVersion"></target>

The final piece of the jigsaw is to add the aforementioned AssemblyVersion target.

	<assemblyversionfiles include="Properties/AssemblyInfo.cs">
<target name="AssemblyVersion">
		<build_number condition="$(BUILD_NUMBER)==''">0</build_number>
	<dateandtime taskaction="Get" format="yyyy-MM-dd HH:mm:ss">
		<output taskparameter="Result" propertyname="BuildDate">
	<tfssource taskaction="GetChangeset" login="CIUser,MySecretPassword">
		<output taskparameter="Changeset" propertyname="ChangeSet">
	<assemblyinfo assemblyinfofiles="@(AssemblyVersionFiles)" 
				  assemblycompany="Example Co" 
				  assemblyproduct="Example Wonderware" 
				  assemblycopyright="Copyright © Example Co 2011-12" assemblyfilemajorversion="$(MajorVersion)" assemblyfileminorversion="$(MinorVersion)" assemblyfilebuildnumber="$(ChangeSet)" 
				  assemblydescription="Wonderware. Revision $(ChangeSet) Built on $(BuildDate)">

Here we use the Jenkins set BUILD_NUMBER environmental variable to be the file revision, or use zero if it’s not present (as it won’t be on developer builds) as the same changeset maybe built multipe times. The MSBuild Extension pack TfsSource task allows us to query the current changeset number which is set as the assembly build number. The extension pack also easily allows us to get the date. Finally we use the AssemblyInfo task from the extension pack to write the various values back into AssemblyInfo.cs.

The nice thing about Visual Studio now relying on MSBuild is you can add all this to the .csproj files and it works seamlessly on both dev boxes using the IDE and the build server using the command line tools.