Versioning Groups of Assemblies in sync

We often build groups of assemblies that all need to be marked with the same build number. Rather than having the build check out a whole bunch of AssemblyInfo.cs files from source control, set their file versions, and check them in, we use Visual Studio .NET's handy and (not widely known) Linked file feature to centralize the version information into a single file. Then the build only has to worry about updating the build number in one place. Here's how we do it.

Create a VersionInfo.cs file in a central place in your source tree.

---VersionInfo.cs---
using System.Reflection;
using System.Runtime.CompilerServices;

[assembly: AssemblyFileVersion("1.0.0.123")]

In each of the projects that need to be versioned in sync, do the following:

  1. Remove the AssemblyFileVersion attribute from AssemblyInfo.cs so you don't have duplicates.
  2. Select Add Existing Item... to the project
  3. In the file-open dialog navigate up to the VersionInfo.cs file and click the little down arrow on the right side of the Open button and select Link File

This will write the following into your csproj file.

---MyProject1.csproj---

<VisualStudioProject>
    <CSHARP>
        <Files>
            <Include>
                <File
                    RelPath = "AssemblyInfo.cs"
                    SubType = "Code"
                    BuildAction = "Compile"
                />
                <File
                    RelPath = "VersionInfo.cs"
                    Link = "..\VersionInfo.cs"
                    SubType = "Code"
                    BuildAction = "Compile"
                />


We use CruiseControl.NET, NAnt and NAntContrib's Visual SourceSafe tasks in our build process. Centralizing the versioning in a single VersionInfo.cs simplifies our build process and guarantees that all assemblies built at the same time will be marked with the same build number.

I did have to write a custom NAnt task that sets the version into the VersionInfo.cs file using a regular expression search and replace. The custom task is called like this:

<!-- label-to-apply property provided by CruiseControl.NET -->
<property name="label-to-apply" value="1.0.0.2"/>
:
<setversion file="VersionInfo.cs" fileVersion="${label-to-apply}"/>

Because I didn't find anything in NAnt or NAntContrib that did anything this simple for me, but maybe I just missed it. Anyway, this system is working quite nicely for us.

6 Comments

  • There is another way to acomplish the same task: create a new project called VersionInfo. In this project, you define your version number as a public const string.

    In all your other projects, you can refer to this project and use the const string in your [assembly...] statements.



    The neat thing is: the VersionInfo DLL is only needed at compile time, not at runtime. This is because the const variables are hardcoded in your assembly, so the DLL that they came from is not needed anymore at runtime. You can check this in ILDASM.



    I've been doing this for quite some time now, and it works perfectly.

  • I don't like the idea of keeping version info with the code. Not even in a shared AssemblyInfo file. That’s only relevant if you build releases directly from VS or some silly thing like that :)



    My preferred method is to store the version in a separate xml file located with the build scripts. During build the ${build.version} is constructed using the nant xmlpeek task and the label-to-apply property set by cruisecontrol.



    The version is set by generating a new AssemblyInfo.cs file (asminfo) which is then used in the csc task. The AssemblyInfo in the project is usually excluded completely unless it has no overlapping attributes.

  • Kristof, how do i use the const string in my [assembly...] statement. Do you have an example?

  • Create a project called VersionInfo

    Add a class AssemblyFileVersion

    Add a public const string Number

    then

    [assembly: AssemblyFileVersion(VersionInfo.AssemblyFileVersion.Number + "24")]

  • Thank you Kristof Verbiest, that is a massively superior way to handle this problem. I did not think you could pull const info out of an assembly like that!

    If you're using nAnt you can auto-generate the assemblyinfo for this 1 assembly and reference it in all subsequent assemblies. No need to mess with the nAnt build script if/when you add additional assemblies.

    Another benefit is that you can pick & choose which assembly attributes you suck out of the common versioner.
    For most of our components I want the product name to be the same, but for some of them I want it to be subtly different.

    This is a particular headache for us, as we have C++.NET, C#, & VB.NET code in our solution.

  • Yes, Kristof Verbiest, that really is most cool.

Comments have been disabled for this content.