Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Managing assembly version numbers using Visual Studio .NET and Visual SourceSafe

0.00/5 (No votes)
25 May 2004 1  
This article discusses how to customize assignment of version numbers to .NET assemblies to fit specific requirements of the development team.

Introduction

This article discusses how to customize assignment of version numbers to .NET assemblies to match specific requirements of the development team. It suggests use of UpdateVersion utility to handle various version assignment policies. It also provides examples of custom scripts that can be embedded in VS.NET project to automatically update files in Visual SourceSafe.

1. .NET version management in brief

.NET approach to component version management is often presented as the end of DLL hell. XCOPY deployment eliminates well-known problems with common component deployment under Windows: newer component versions are assumed to be backward compatible with old ones, therefore overwriting them in a shared component storage (like Windows System32 folder). However, backward compatibility is just an ideal scenario that does not always occur in reality.

.NET default assembly treatment is very strict, and it must be. Once the assembly is assigned a strong name (and common assemblies should), its clients will require the same assembly version that was used during the build. In case other versions are accepted, this has to be explicitly stated in so called version policies (stored in configuration files), or assembly publisher policies (stored in GAC). Such approach to version policy management makes it impossible for wrong assembly version to be accepted by its client. It is safer to deny execution of potentially incompatible code than to believe that a different version of the component will work.

Visual Studio .NET follows this approach, and unless exact static assembly version is assigned to a component, the new version will be generated for each build. This is achieved by placing the following version string in one of the assembly source files:

[assembly: AssemblyVersion("1.0.*")]

Asterisk sign instructs Visual Studio to assign on each build a version 1.0.d.s, where d is the number of days since February 1, 2000, and s is the number of seconds since midnight/2.

So, what�s the problem then? Shouldn�t we just use standard Visual Studio version handling, since it guarantees that assemblies with strong names will only be used with the code that is built to use specific versions? Well, this is a most reasonable default behavior, but in some cases, it can be inconvenient to handle. Let�s see when.

2. What can go wrong?

When the number of projects grows, they will most likely be split into multiple solutions, with some of the projects contained in several solutions. So, if you have two applications, A and B, and both of them use a strong-named assembly C with utility code, you will have the following project structure:

Solution A
    Application A
    Class library C

Solution B
    Application B
    Class library C

As long as you deploy them in different folders, everything will be fine. But if you package applications A and B to be deployed in the same folder, then one of the copies of C will be overwritten, which will prevent its corresponding application to run. Of course, this situation can be handled by version policy files, but it is the same version of the class library source code that is used to compile solutions A and B, it was just compiled twice in different solutions. We want two copies of assembly C to have the same version, don�t we?

But why don�t we then assign the explicit version? Just replace wild card with exact build and revision number, for example 1.0.0.1, won�t it help? Well, yes and no. Sure, it will resolve versioning problem, but leaves a risk for a simple human mistake: what if I update assembly source code and forget to assign a new version number? Then I will have different assemblies with the same version numbers assigned. So, it�s actually not bad that some tools like Visual Studio does this job for us and stamps different versions of assemblies differently. It�s just that we may want to customize its version update scheme.

3. Customizing version update: UpdateVersion

So, which version update scheme will fit best in a development team with large number of projects combined in multiple solutions? In our team, we run daily builds, so we decided that major and minor versions are always managed manually (not an unreasonable decision), and build number should be managed automatically and assigned to the day count (this is what Visual Studio does with wild card). However, to avoid incompatibility problem described in a previous section, revision number is fixed and set to 0 (can be set to any other number if needed). So, our scheme is actually maj.min.*.0. The only problem is that such a scheme is not supported by .NET: you can�t let compiler manage build number and have static revision number. We needed an external tool.

Although it was tempting to write our own utility, a quick search in Google referred us to an excellent .NET command-line tool UpdateVersion written by Matt Griffith and Scott Hanselman (extra feature added by Mike Gunderloy). It�s a nice application written entirely in C# using .NET regular expression classes. UpdateVersion supports variety of schemes, and you will certainly find the one that fits your team. And if not? Well, add your own � it comes with source code and gives you right to modify it as long as you accept its license terms. UpdateVersion and its source can be downloaded here.

To apply our version update pattern (maj.min.*.rev) we used UpdateVersion command-line options -b BuildDay -r Fixed. With these options, if you run UpdateVersion on May 25, 2004, it transforms input AssemblyVersion(1.0.0.0) to AssemblyVersion(1.0.4146.0). This will guarantee that all assemblies built during the daily build will have the same build.revision number, no matter how many times the assembly is recompiled during the same build.

4. Automating version update

Next step is to embed UpdateVersion invocation into the .NET project the version of which needs to be handled this way. This is achieved by adding Pre-built event to the project properties. Activate project properties dialog, then select Common Properties -> Build Events. Type the following text in Pre-build Event Command Line text box:

UpdateVersion.exe -b BuildDay -r Fixed -i 
      $(ProjectDir)\AssemblyInfo.cs -o AssemblyInfo$.cs
move AssemblyInfo$.cs $(ProjectDir)\AssemblyInfo.cs

Of course, UpdateVersion.exe must be copied to a directory listed in PATH environment variable.

6. But the source code must be checked out!

It would be too easy if the previous step was sufficient in most cases. And in most cases, it doesn�t � you are using version control system, aren�t you? Then you are like me, and we need to extend our build script to check out AssemblyInfo.cs file before updating the version number and checking it in afterwards. Here�s an updated text for Pre-build Event Command Line for those who use Visual SourceSafe as their version control software:

UpdateVersion.exe -b BuildDay -r Fixed -i 
      $(ProjectDir)\AssemblyInfo.cs -o AssemblyInfo$.cs
fc $(ProjectDir)\AssemblyInfo.cs AssemblyInfo$.cs > nul
ss CP "$/<MyProject>"
ss checkout -GL$(ProjectDir) AssemblyInfo.cs
move AssemblyInfo$.cs $(ProjectDir)\AssemblyInfo.cs
ss checkin -GL$(ProjectDir) -C"Version number" AssemblyInfo.cs

NB! You need to replace <MyProject> with the fully qualified project path in Visual SourceSafe. Also, make sure SourceSafe binary directory is listed in PATH environment variable, and another environment variable SSDIR points to a directory that contains SourceSafe database (the one with file srcsafe.ini).

Command ss CP� selects current SourceSafe project. Command ss checkout� checks the specified file from current SourceSafe project and copies it to the current directory. Finally, after the file is updated, command ss checkin� checks the file in. Option -G.

7. Check out every time I build? No, thank you.

Yes, this can be rather irritating. I can compile some of my projects hundred times a day, and the fact that now each compilation will invoke SourceSafe does not make me happy. I would accept it if the actual version was different, but it changes only once a day. We need to optimize this step. And it can be done very simple.

Built-in Windows command-line utility fc (File Compare) returns different values depending on the result of file comparison. If it does not encounter any differences, it returns 0, but if the files are different, it returns 1. Let�s use this knowledge to improve our script:

UpdateVersion.exe -b BuildDay -r Fixed -i 
      $(ProjectDir)\AssemblyInfo.cs -o AssemblyInfo$.cs
fc $(ProjectDir)\AssemblyInfo.cs AssemblyInfo$.cs > nul
if %errorlevel 1 goto checkout
del AssemblyInfo$.cs > nul
goto end
:checkout
ss CP "$/<MyProject>"
ss checkout -GL$(ProjectDir) AssemblyInfo.cs
move AssemblyInfo$.cs $(ProjectDir)\AssemblyInfo.cs
ss checkin -GL$(ProjectDir) -C"Version number" AssemblyInfo.cs
:end

As you can see, the Pre-build script is now more complex and it includes conditional statements. Newly generated AssemblyInfo.cs file is compared with the original, and if files are identical (result of comparison is 0), the generated file is simply deleted and script terminates. However, if files are different (which means that assembly was not compiled today), it proceeds with check-out followed by file update and check-in.

Conclusion

The demonstrated technique will not always fit in your development environment. Perhaps, the way you assign versions to assemblies is different, or your source control management is different. However, the idea of this article was to demonstrate that with minimal changes (and no changes to your source code), you can easily customize version assignment policy to avoid manual intervention to build and deployment processes.

Resources

  1. Don Box with Chris Sells. Essential .NET. Volume 1. (Chapter 2. Components)
  2. UpdateVersion User Guide.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here