Thursday, July 15, 2010

The Right Way to Version Your Assemblies

No, I'm not talking about whether you have Major, Minor, Patch, and Build numbers.  I'm not talking about when you increment which number.  My suggestion is to do whatever works for you in those cases, though I reserve the right to blog about that in the future.
What I am talking about is how you can structure your solution and project files in Visual Studio to make updating your assemblies' version number much easier.
This blog post makes some assumptions:
  • You are using version numbers in your assemblies
  • You are using a recent version of Visual Studio (I know these steps work with both Visual Studio 2008 and 2010)
  • You have multiple assemblies in one Visual Studio solution
  • You want to update all of your assemblies' version numbers at the same time and to the same version number
Those assumptions cover a vast majority of the projects I've worked on, but I'll admit that there may be projects out there that might not fit into the mold I've set forth.  I'm OK with that.  This blog post isn't for you if your mold is different.
So let's get started.
I created a solution file which contains several 1-OriginalSolutionExplorerprojects.  There's an MVC2 web application project, its associated test project, a business objects project, and a data access layer project.  These are all empty projects for this example—only the structure of the solution and projects is important for my purposes.  Solution explorer for this project is shown here.
The first step is to separate out the version information (and any other information that is common from assembly to assembly if you wish, like company name, product name, and so on) into its own file.  Open up one of the AssemblyInfo.cs files to see what I'm talking about.
2-OriginalAssemblyInfo
Notice that the settings are assembly attributes.  Some people don't realize that you don't have to put all the assembly attributes in one file.  I'm going to take advantage of that fact to accomplish what I set out to do: change the version in one place and have all projects updated at once.  The other key is using a solution-level file and linking to is from each project.
Visual Studio supports files at the solution level as well as at the project level.  You can put anything you want at the solution level and it will be carried along with the solution, though it won't get included in any output unless you write some custom build rules to grab the file and do something with it.  On some projects I've included a Word document about the solution and its projects as a solution level file.
For this example, we're going to create a new C# source file and include it at the solution level.  I'm going to call this new file, "VersionInfo.cs".
Step 1: Create a new file and call it "VersionInfo.cs".  Do this by choosing "File | New | File…" or press Ctrl-N in Visual Studio.  Choose "Visual C# Class" as the file type.
3-CreateVersionInfoCsStep 2: Erase everything in this file.  Save it as VersionInfo.cs in the same folder as the solution file.
Step 3: Highlight the version information lines from the AssemblyInfo.cs file from earlier, cut it from that file (Ctrl-X) and paste it in VersionInfo.cs (Ctrl-V).  Add "using System.Reflection;" to the top of VersionInfo.cs to avoid compilation errors.
4-SolutionItemsFolder Step 4: Add the VersionInfo.cs file to the solution by right-clicking on the solution file, choosing "Add | Existing Item…", then selecting "VersionInfo.cs" (find it in the solution's folder where you just saved it), and then click "Add".  You should see a new "Solution Items" folder under your solution name with the VersionInfo.cs file in it (see screenshot).
Step 5: Add the VersionInfo.cs file to each project as a linked file. See below for instructions on how to do this.
Step 6: Remove the version information from the other projects' AssemblyInfo.cs files.
At this point you should be able to build your solution successfully, and each assembly should have the same version information—the information found in VersionInfo.cs.
So what is a "Linked File" and how do I create one?  Read on.
Right-click on the project and choose "Add | Existing Item…", navigate up one folder level, and click once (don't double-click!) on the VersionInfo.cs file.  [This assumes that your solution folder is one level up from your project 5-LinkedFilefolder!]  Now instead of clicking "Add", click the little down-arrow next to the "Add" button.  Choose "Add As Link".  You should now see VersionInfo.cs in your project, but with a "shortcut" icon overlaid on top of the file's icon.
Once you have completed this step for each project, you can build your solution without errors.
Now to test it out.  Build the solution and look in the bin folder (or "folders" if you haven't added the other projects as references in the web project) for the DLLs.  Look at the version numbers.  They should all read "1.0.0.0".
Now change the version number in the VersionInfo.cs file information.  Rebuild the solution then check the version numbers.  All of the assemblies should now have the new version number.
6-DLLProperties Notice, however, that it is the "File Version" that you see when hovering over the DLL in Windows Explorer, so if you change only the "Assembly Version" the you'll have to go to the DLL's properties to see your change.
[I must admit, I don't recall which version number is used when putting DLLs into the Global Assembly Cache.  Please leave a comment if you have that information handy!]
So that is the procedure.  If you have an automated build system then you can make use of the fact that the version number is in its own file and update it automatically.  Then each build will produce DLLs with distinct version numbers.  That is a great way to identify the build that a DLL came from if you happen to get a report from the field that there is an error in a specific DLL.
But I'm sure that's never happened to you…right?
[Update: adding to ]