Follow us on Twitter
Follow us in Facebook
Office Dev Content
SharePoint Dev Content
In this fourth article of our SharePoint Continuous Integration series, we will look at how to implement assembly versioning as part of a Team Foundation Server (TFS) build. Versioning refers to changing the version number or name with each new release of code. Versioning is important because it enables you to easily see which version of a piece of code is installed in a particular environment. On the .NET platform, the version is typically represented as a four-part number, starting with 1.0.0.0 by default, that exists on each .NET assembly. Incrementing the version can be done manually, but where an automated build process exists (such as in a nightly build), it’s beneficial and a common practice to make versioning an automated step. Note that in TFS 2010, there is no simple configuration switch to enable versioning; some customization of the build process is required. This post provides a step-by-step guide for customizing the build process.
Although assembly versioning is a common practice in the .NET world it brings certain challenges in SharePoint, and this necessitates some changes to the approach outlined in many internet articles. The next section explores this, and the remainder of the article provides detailed steps and sample code to implement versioning for SharePoint projects in a TFS 2010 build definition. Note that the code provided here is a derivative of the excellent work done by Jim Lamb (TFS Program Manager). His post Create a Custom WF Activity to Sync Version and Build Numbers is a good place to check if you’d like more detail on the implementation.
Assembly versions are everywhere in SharePoint – web.config files, web part definitions, workflow definitions, event receiver bindings – the list goes on. In each case, the version number is absolutely required so that SharePoint can load the code to run at that time. If you update an assembly’s version, you have two choices to ensure your code can still be loaded:
The first option is impractical, and although the second one is certainly possible – especially since SharePoint 2010 introduced support for adding binding redirect entries to config files during WSP deployment – it’s still not ideal. One reason for this is that binding redirects often aren't added to other config files where they might be required, a prime example being the config file for the SharePoint Timer Service, owstimer.exe.config.
Given these challenges, a better approach is to leave the main assembly version unchanged and instead increment the value of the “assembly file version” property. This is effectively a secondary version number which is not used by .NET in assembly binding. The KB article How to use Assembly Version and Assembly File Version has more details on differences between the two attributes. Using assembly file version means we get the benefits of easily identifying the version of an assembly (without having to take other steps, such as decompiling code), but without the hassle of having to update references to assembly names. Whilst the main assembly version will still show “1.0.0.0”, to see the version number of an assembly versioned in this way, simply right-click the file and view its properties. Under most circumstances, the incremented version number appears in the File version field. The exception to this case is when you wish to include a string in the assembly version – some teams like to include the build name, date or other string-based information as part of the version number. In this case, File version will be set to “0.0.0.0” and the Product version attribute will instead show the generated assembly number. This is the case in the image below where we use TFS 2010’s default build number convention of [build name]_[date in reverse format].[auto-incrementing revision number]:
To emphasize, the sample activity code linked to in this article takes the build number assigned by TFS during the build and applies it to the assembly version attribute(s). One benefit of this approach is that if the build is configured to apply a source control label to each release, this value will also become the assembly version. This method not only makes it easy to identify the version of an assembly in a particular environment, but also makes it possible for the developer to easily get the original files comprising the build. This can be accomplished by using the “get by label” command, rather than a "get latest" or "get changeset".
Implementing versioning in TFS Build typically revolves around adding a custom activity into the workflow. Notably, TFS 2010 Build runs as a .NET 4 workflow – meaning any custom activities must be written using .NET 4 code in an environment which has this version of the .NET Framework installed. In this case, the activity’s code performs the same steps as a human would to increment the assembly version, namely editing the AssemblyInfo.cs (AssemblyInfo.vb for VB.NET) file, and there are several articles published which detail this. The main difference with this guidance is that the implementation is flexible enough to suit SharePoint builds. The activity enables you to configure whether the main assembly version and/or the assembly file version is updated. (Updating the assembly file version is recommended for SharePoint builds.):
To implement versioning in your build workflow, you have two options:
This article provides a pre-built activity. Before running through the detailed steps to use this activity in your build workflow, however, consider that what we broadly need to achieve is the following:
Use the following process to add the activity to your workflow. Note that some steps (marked) require a development machine running .NET 4:
The next steps must be performed on a development machine that has Visual Studio 2010 and .NET 4 installed. This is because TFS 2010 workflows are .NET 4 workflows and the sample assembly is a .NET 4 assembly.
The other option is to add global arguments at the workflow level, to allow configuration of these options without opening and editing the workflow definition itself. The first step of this option is to add the arguments through the Arguments tab: Once the arguments have been defined, edit the properties of the "UpdateAssemblyVersionNumber" activity to read from the values of these arguments: The two parameters should now be exposed on the build definition, meaning no editing of the workflow XAML is needed to change the values:
The other option is to add global arguments at the workflow level, to allow configuration of these options without opening and editing the workflow definition itself. The first step of this option is to add the arguments through the Arguments tab:
Once the arguments have been defined, edit the properties of the "UpdateAssemblyVersionNumber" activity to read from the values of these arguments:
The two parameters should now be exposed on the build definition, meaning no editing of the workflow XAML is needed to change the values:
If everything is correctly configured, assemblies will now be automatically versioned by the build. The build report should indicate that the "Update Version Info in File" activity is called for every assembly being built:
It should now be easy to identify the version of an assembly in any given environment. Simply right-click the assembly and view its file properties, and the auto-generated version number will appear in the attributes (shown in earlier image). Integrating the versioning of assemblies as part of a build process can be a significant step forward for a development team seeking to improve code and release quality.