Assembly and Assembly file version numbers

Hi everyone.

Here's an email I recently posted to a respected guy at MS named Vincem (http://blogs.msdn.com/vincem/). I'd like to post this same mail here to see what other people are doing with regard to .Net assembly version attributes.

I'm doing a spot of research in an attempt to make an informed decision regarding versioning of .Net assemblies. I've read (and re-read) the blog entries you kindly posted (http://blogs.msdn.com/vincem/archive/2005/04/01/404441.aspx) as part of this research. It seems to me there is little consensus on whether to keep the assembly and file version the same or different for .Net assemblies. Looking at a number of open source projects (NUnit, NAnt, ccnet) it seems common practise (perhaps for simplicity ) to use the same version number for both. Reading around it appears that Jeffrey Richter (Applied MS .Net Framework Programming) also shares your opinion. So what to do

My main concern with using a different number for AssemblyVersion and AssemblyFileVersion is as follows:

Apparently, installing a .Net assembly into the GAC using MSI will *not* overwrite an assembly with the same assembly version (ie the same strong name), but different file version number, unless you start getting fancy with the MsiAssemblyName table and add the appropriate FileVersion property. I think this creates a problem in a small agile team that's using Continuous Integration (CI). In practise a CI build is not the same as a release build that is run nightly. However, the build artifacts from a CI build is often used to deploy to a test machine when a "quick fix" is required during the day. To this end it appears to be common practise to create a distribution package from a CI build. If this distribution is an MSI package, then you can immediately see the problem - it won't actually overwrite the existing assemblies in the GAC.
I'm really rather new to the .Net world and Windows Update technology, but this seems to imply that to get around this problem the all builds must either increment the assembly version in line with the file version number or conditionally inject a FileVersion property into the MsiAssemblyName table dependent on the type of build - the CI build injects a FileVersion property while the nightly build increments the AssemblyVersion (not sure how this can be done in an automated fashion).

I would really appreciate it if you could compose a reply outlining what you think re the points I make above.

Thanks in advance

Christian Crowhurst (UK Developer)


Answer this question

Assembly and Assembly file version numbers

  • Tony Leung

    Hi Christian,

    It might be useful for you to read Suzanne Cook's blog (http://blogs.msdn.com/suzcook).  She's got a post that might interest you entitled "When to Change File/Assembly Versions" (http://blogs.msdn.com/suzcook/archive/2003/05/29/57148.aspx).

    -Shawn

  • WallyLawless

    I've been told that strictly speaking this is just the way that Fusion behaves when asked to add an assembly to the GAC, although this is an artificial distinction as far as the end-user is concerned (I guess I'm defending MSI here!). It's just an example of the way in which MSI and the GAC don't seem very well integrated. Assemblies aren't in the GAC until the "end" of the install, as another example.
    The GAC idea that new file versions don't replace older versions has always seemed weird to me - it turns on its head many years of installation behavior, as well as the fact that outside the GAC new file versions DO replace older versions. Anyway I'm repeating what's in that blog entry.
    Beware of this bug too:
    http://blogs.msdn.com/astebner/archive/2005/02/12/371646.aspx

  • falconair

    Frank,
    Thanks for taking the time for this conversation. You're reasoning is sound and well balanced. I've heard the same pros and cons voiced by a fair number of people. And I think this is perhaps why there is no common consensus as to how to proceed. If one versioning scheme just had cons then the choice would be simple.

    Given that things are not clear cut I think the decision must be made on a case-by-case basis giving consideration to the domain. The setup that I think is optimal for our domain is:
    - to increment the FileVersion on each and every CI build (and of course on the nightly build).
    - to increment the AssemblyVersion on the nightly build. This does mean that I have to figure out how to automate the creation of the installer that will perform an in-place update for the CI build and a side-by-side installer for the nightly.

    This way a patch to a single assembly spat out by the CI build can be deployed to a QA server during the day without having to redeploy the entire system. Whereas a nightly build will increment the entire system - client and server components - with the same AssemblyVersion (assuming something has changed during the day)

    We have full control over when a client deployment can and should happen and the intention here is to automate client updates. If we did not have this control then incrementing the AssemblyVersion on a breaking change does sound enticing. However, it would be very much against MS "recommended" practise (see http://blogs.msdn.com/mgrier/archive/2004/04/15/113663.aspx). Another problem I can see with the pattern "Update on a breaking change" - it relies on developers to flag when they have broken backwards compatibility, something that I see as a very big risk.

    So in conclusion I think its means I've got to bite the bullet and delve into how to automate MSI to conditionally create an in-place or side-by-side installer. Recommended reading anyone

    Thanks
    Christian

  • Ola Sprauten

     christianacca wrote:
    Hi Frank,
    This behaviour from MSI only becomes an issue when you start to use different version numbers for AssemblyVersion and AssemblyFileVersion. If you were to keep them the same, the AssemblyVersion would get incremented on each build and therefore each distribution would create a side-by-side deployment (assuming you're using strong named assemblies).
    If we are putting assemblies in the GAC then we are using strong named assemblies.

    Also, if we are putting assemblies in the GAC that meams we believe the assemblies will be shared by several clients and not shared by having separate private copies of the shared assembly in each of those client's base path.  Else why put them in the GAC in the first place

    Under such shared assembly circumstances, it is (I suggest) difficult to deploy hotfixes if the assembly version changes with every build. 

    When the assembly version changes the strong name changes.  If you just deploy your hotfix and stick it in the GAC then all the clients will continue using the old assembly they were using before the hotfix was installed because they are still binding to the old assembly's strong name. 

    Of course you can create and publish a binding policy that redirects requests for the old assembly o the new one.  But that's more work for the build and more work for the install. 

    Plus, as you ship more hotfixes, you now have all these stale assemblies piling up in the GAC with no easy way to get rid of them.  I don't think you can use Windows Installer reference counting to detect when a particular version of the assembly is no longer being used and can be uninstalled.  Whatever clients were installed as using the shared assembly are still installed so the shared assembly seems to be in-use by that client (from a Windows Installer use count point of view) even if the binding policy means it isn't really being used.

    I'd argue you keep the Assembly Version constant until a breaking change is made to the assembly.  Something that invalidates old clients, or makes new clients incapable of running with the older assembly.  Then you change Assembly Version because it really is a different assembly.

    File Version you change with every build, and change significantly when you change Assembly Version. 

    That's what Microsoft appear to do (or at least appear to have done so far).

    Consider a system with the 1.1 Framework and its SP1 installed.  All the .NET Framework 1.1 assemblies have an Assembly Version of 1:0:5000:0 just as they did when 1.1 shipped.  But some of those files are from the service pack not from the original shipment.  The original files seem to have a File Version of 1.1.4322.573.  The later files seem to have a Build Version of 1.1.4322.2032 and at least one file (a subsequent hotfix ) has a Build Version of 1.1.4322.2037.

    Assembly Assembly version File Version Modified
    System.Drawing.Design 1:0:5000:0 1.1.4322.573 2/21/2003
    System 1:0:5000:0 1.1.4322.2032 7/15/2004
    System.Web 1:0:5000:0 1.1.4322.2037 10/8/2004

    There is one advantage to changing Assembly version at every build.  It does give you more flexibility to avoid "dll hell" type problems.  With every build a different strong name and a different assembly version you can use redirection to point any client assembly at any other version of the assembly that's being built.  That means if you release a hotfix that breaks some other program you can redirect (or re-redirect) the broken program back to the older pre-hotfix version of the assembly.
  • Tillmann

     christianacca wrote:
    Thanks for taking the time for this conversation.
    Blatant self interest.  Writing it down helps me figure out what I think too.

    So in conclusion I think its means I've got to bite the bullet and delve into how to automate MSI to conditionally create an in-place or side-by-side installer. Recommended reading anyone
    I don't know if it covers your question specifically (my copy is out on loan) but I think The Definitive Guide To Windows Installer by Phil Wilson is a good book for Windows Installer questions in general.  Full disclosure: Phil is a colleague and a fellow ex-patriot Brit so I might not be entirely objective. 

    http://www.amazon.com/exec/obidos/tg/detail/-/1590592972/qid=1119389136/sr=8-1/ref=sr_8_xs_ap_i1_xgl14/103-1066055-6672643 v=glance&s=books&n=507846

  • DR_CHAOS

     christianacca wrote:
    My main concern with using a different number for AssemblyVersion and AssemblyFileVersion is as follows:

    Apparently, installing a .Net assembly into the GAC using MSI will *not* overwrite an assembly with the same assembly version (ie the same strong name), but different file version number, unless you start getting fancy with the MsiAssemblyName table and add the appropriate FileVersion property.

    I believe the WindowsInstaller behaviour is wrong.  If you use GACUTIL instead of Windows Installer you'll find that GACUTIL does overwrite.

    Of course that's of limited use if you are trying to build a robust MSI but I'd argue that GACUTIL was built by the .NET Framework SDK team and so more accurately reflects what the .NET framework folks think should happen.  

  • Jake kim

    Installing an assembly into the GAC seems to be a recurring problem. I am not sure why MS does not make this more obvious.

    I know this thread is an old one but I can not find any other place to put my question. I want to install an assembly into the GAC using Visual Studio .NET 2005. MS says it can be done but I can not find any place where MS says HOW it can be done. Does anyone know


  • CMichaud

    Project\Properties\Build Events\Post Build Event Command Line:

    "C:\Program Files\Microsoft Visual Studio 8\SDK\v2.0\bin\gacutil" /i $(TargetPath)

    Run the post build event:

    On successful build


  • cashfoley

    If by "with Visual Studio .NET 2005" you mean with a Setup&Deployment project, go to File System on Target Machine, right click that node, Add Special Folder, and choose the GAC. Then you can use it as a file destination.

  • Kolokolov

    >Blatant self interest.  Writing it down helps me figure out what I think too.

    Ah, so its not just me who thinks this way :-)

    Thought I recongnised the name of your colleague (Phil Wilson happened to have some interesting comments here: http://blogs.msdn.com/alanshi/archive/2004/03/28/100765.aspx)

    I'll check out the book - thanks for the advise.

    C

  • Spidermans_DarkSide

    Hi Phil,
    From reading posts from certain ms guys, in-place updates should never be allowed so as to avoid, amongst other things, an uninstall from leaving behind ungraded shared dll's. I admit I can see their point. But then as Frank points out, ms themselves do not adhere to these rules! Add to this a lack of comprehensive guidance over at patterns&practises, no wonder this area is confusing.

    Another area of consternation I'm having is deciding when to use the same version number across multiple assemblies. The general advise is to use the same (AssemblyVersion) number for all assemblies making up your business project. I think this is rather simplistic advise. For a start, a win or web vs.net project will often lag slightly (by a couple of hours to a couple of days) behind changes to the library project that encapsulates the business logic. Next, a vs.net project may be common to a number of business projects that have quite different lifecycles. Finally you may not have control over when a client side install can take place. All these situations point to a vs.solution per vs.net project / assembly and therefore a version number per assembly. The only useful comment I've seen is to apply the same number to the AssemblyInformationalVersion for all assemblies making up the business project at the point when you build a public release. Hell why isn't there more advise in this area Its taken me probably a dozen evenings scratching around for info! Ok, ranting over. Frank / Phil, feel free to chip in with the definitive guide ;-)

    Christian
    P.S - thanks for the link to the bug

  • Jinnyminto

    Hi Frank,
    This behaviour from MSI only becomes an issue when you start to use different version numbers for AssemblyVersion and AssemblyFileVersion. If you were to keep them the same, the AssemblyVersion would get incremented on each build and therefore each distribution would create a side-by-side deployment (assuming you're using strong named assemblies).

    For this reason I'm inclined to use the same number and avoid the issue of trying to get MSI to perform an in-place assembly update. However, this flies in the face of what Vincem and Jeffrey Richter recommend which makes me think twice.

    Problem is I'm not well placed at the moment to investigate fully how to automate the creation of an MSI which performs an in-place update *or* a side-by-side installer. Also I'm concerned that having to create both an in-place and a side-by-side distribution will result in two installer projects and therefore a maintenance problem. I suppose the alternative would to use another installer technology but I'm reluctant to do this also :-(

    Christian

  • Assembly and Assembly file version numbers