When to Change File/Assembly Versions

First of all, file versions and assembly versions need not coincide with each other. I recommend that file versions change with each build. But, don’t change assembly versions with each build just so that you can tell the difference between two versions of the same file; use the file version for that. Deciding when to change assembly versions takes some discussion of the types of builds to consider: shipping and non-shipping.

Non-Shipping Builds
In general, I recommend keeping non-shipping assembly versions the same between shipping builds. This avoids strongly-named assembly loading problems due to version mismatches. Some people prefer using publisher policy to redirect new assembly versions for each build. I recommend against that for non-shipping builds, however: it doesn’t avoid all of the loading problems. For example, if a partner x-copies your app, they may not know to install publisher policy. Then, your app will be broken for them, even though it works just fine on your machine.

But, if there are cases where different applications on the same machine need to bind to different versions of your assembly, I recommend giving those builds different assembly versions so that the correct one for each app can be used without having to use LoadFrom/etc.

Shipping Builds
As for whether it’s a good idea to change that version for shipping builds, it depends on how you want the binding to work for end-users. Do you want these builds to be side-by-side or in-place? Are there many changes between the two builds? Are they going to break some customers? Do you care that it breaks them (or do you want to force users to use your important updates)? If yes, you should consider incrementing the assembly version. But, then again, consider that doing that too many times can litter the user’s disk with outdated assemblies.

When You Change Your Assembly Versions
To change hardcoded versions to the new one, I recommend setting a variable to the version in a header file and replacing the hardcoding in sources with the variable. Then, run a pre-processor during the build to put in the correct version. I recommend changing versions right after shipping, not right before, so that there's more time to catch bugs due to the change.

Comments

  • Anonymous
    June 19, 2003
    The comment has been removed

  • Anonymous
    June 19, 2003
    Yes, strongly-named assemblies already in the download cache will not be downloaded again if the assembly identity hasn't changed. To deal with this, our test scripts delete the download cache at the beginning of the test (gacutil /cdl). We find it preferable to make a one-time change to do that in scripts than to deal with the constant pains of changing versions often.

  • Anonymous
    July 07, 2003
    Ok, that makes sense and is easy enough to deal with. But I'm pretty sure we experienced problems even when all assemblies are loaded locally (and so the download cache hadn't been used), and that clearing the shadow copy cache resolved the problem. Are you aware of similar identity issues with the shadow copy cache?

  • Anonymous
    July 08, 2003
    Yes, they're basically the same thing from Fusion's perspective.

  • Anonymous
    September 17, 2003
    The comment has been removed

  • Anonymous
    September 18, 2003
    Answers to your specific questions below, and they include the answer to your overall question: (1) No, GAC assemblies are required to be in the GAC location. (2) You can make it work. First, make sure that the files in the different directories each have unique binding identities (see http://blogs.msdn.com/suzcook/archive/2003/07/21/57232.aspx ). Then, if you want all these dirs probed, (and you have control of the AppDomain(s) using these assemblies,) use their common parent dir as the AppDomainSetup.ApplicationBase, and the list of subdirs as the PrivateBinPath. But, probing the dirs won't help for multiple files of the same name, but in different dirs. You will need to have a config file with one codebase redirect for each of them, or else you'll get a FileLoadException. That will avoid probing, but causes a new FileIOPermission.Read and PathDiscovery demand on the given path. (3) Ideally, they'd be in the GAC. But, besides that, if you have control over the calling code, you could have it pass you the outside dir. If you don't have that control, you could set the dir in the registry. (4) I believe no.

  • Anonymous
    October 06, 2003
    The comment has been removed

  • Anonymous
    November 26, 2003
    The comment has been removed

  • Anonymous
    December 04, 2003
    The comment has been removed

  • Anonymous
    January 27, 2004
    I have a doubt with multiple versions of same assemblies in GAC.How do i access both??

    For example, if i have a assembly A with a method say func1 and i put it in GAC.

    No i build a new version of the same assembly and put it in GAC with a new method func2.

    If one of my application wants funct1 of Ver1
    and func2 of Ver2 how do i go about this??

    If i add as a reference to the assembly with VS .NET it points me to Ver2.

    How do i access the Ver1.

    Thanks in advance.

  • Anonymous
    January 28, 2004
    First, make sure that the two versions have different assembly identities. See http://blogs.msdn.com/suzcook/archive/2003/07/21/57232.aspx . Probably, this means that you will want to give them different assembly versions and strongly name them.

    Second, if you want a static reference, you will need to use a compiler that supports it. (I don't believe any of the pre-v2.0 VS.NET compilers did.) The CLR has always supported that, so once it's been compiled with the references you want, it will just work at runtime.

    You can also do this dynamically, to avoid the need for compiler support. For example, you could get the two Assembly objects using Assembly.Load() with the appropriate display names, and invoke the appropriate methods.

  • Anonymous
    July 21, 2004
    Makes sense. But, how do I update the FileVersion info for my .NET project/assembly?

  • Anonymous
    January 19, 2006
    Regarding shipping and non-shipping builds - I work on a web portal product for which we have one production environment out there on the www and a few other internal testing environments. In our source control, we have a branch which represents each one of these testing environments including live - we build on each of the branches to produce a deployment to that environment only i.e. builds on the Dev branch are only ever deployed to the Dev environment, builds on the Live branch are only ever deployed to the Live environment etc. Furthermore, every build is always then deployed to that environment. I am trying to apply your shipping analogy to my situation. Either the only production/shipping builds occur on the Live environment branch, therefore I change the assemblyversion for everybuild on this branch and every build on any of the testing branches is a non-shipping build therefore the assemblyversion never changes; or every build on every environment is a shipping build therefore always change the assemblyversion. I would welcome any feedback you have on this, I was trying to avoid having the same assemblyversion numbers across different environments but presumably I could use the fileversion to distinguish between environments with a 'dev_' or 'live_' prefix for example

  • Anonymous
    January 24, 2006
    Great conversation everyone, thanks. At our shop, we created a special build program that builds releases for our customers (and development builds). The QA manager just puts in a release version number and presses a button and our collection of projects and solutions representing our product and deployment items is built (I'll need to readup on vs2005 team server to see if I can ditch my custom program). For the idea of the "invoke a preprocessor" to change version numbers... well that is exactly what we do. It is pretty much boilerplate code, but I'm happy to share a couple methods (C#) that I have extracted for you fine people to use in your own preprocessors if you like -- no warranties mind you, just trying to be helpful. (I have no idea how this blog may reformat this code, so apologies to all if it is messed up)


    Method to change AssemblyVersion :

    private void FixupAssemblyVersion(string FileName, bool Force, string NewProductVersion)
    {
    string str;

    using (StreamReader fp = new StreamReader(FileName))
    {
    str = fp.ReadToEnd();
    }

    string pattern;

    if (Force)
    pattern = @"AssemblyVersion(""[^""]"")";
    else
    pattern = @"AssemblyVersion(""[^""]**"")"; // last part of Version must be "
    " unless I'm forcing the new version in

    string str1 = Regex.Replace(str, pattern , @"AssemblyVersion(""" + NewProductVersion + "")", RegexOptions.Singleline);

    if (str1 != str)
    {
    using (StreamWriter fp = new StreamWriter(FileName))
    {
    fp.Write(str1);
    }
    }
    }



    Probably more interesting method for everyone else, this will update the version number in a setup deployment project, as well as generate new product and package code guids.

    private void FixupSetupProjectVersion(string FileName, string NewProductVersion)
    {
    // Setup projects can have a 3-part version (not a 4-part version)
    StringBuilder sb = new StringBuilder(300000);

    using (StreamReader fp = new StreamReader(FileName))
    {
    string ProductVersionPattern = @"""ProductVersion"" = ""8:";
    string ProductCodePattern = @"""ProductCode"" = ""8:{";
    string PackageCodePattern = @"""PackageCode"" = ""8:{";

    string NewProductCode = System.Guid.NewGuid().ToString("").ToUpper();
    string NewPackageCode = System.Guid.NewGuid().ToString("").ToUpper();

    while (true)
    {
    string s = fp.ReadLine();
    if (s == null) break;

    if (s.IndexOf(ProductVersionPattern) >= 0)
    {
    int i1 = s.IndexOf(ProductVersionPattern);
    i1 += ProductVersionPattern.Length;
    int j1 = s.IndexOf(""", i1);

    string s1 = s.Substring(0, i1) + NewProductVersion + s.Substring(j1, s.Length - j1);

    sb.Append(s1 + "rn");
    }
    else
    if (s.IndexOf(ProductCodePattern) >= 0)
    {
    int i1 = s.IndexOf(ProductCodePattern);
    i1 += ProductCodePattern.Length;
    int j1 = s.IndexOf("}", i1);

    string s1 = s.Substring(0, i1) + NewProductCode + s.Substring(j1, s.Length - j1);

    sb.Append(s1 + "rn");
    }
    else
    if (s.IndexOf(PackageCodePattern) >= 0)
    {
    int i1 = s.IndexOf(PackageCodePattern);
    i1 += PackageCodePattern.Length;
    int j1 = s.IndexOf("}", i1);

    string s1 = s.Substring(0, i1) + NewPackageCode + s.Substring(j1, s.Length - j1);

    sb.Append(s1 + "rn");
    }

    else
    {
    sb.Append(s + "rn");
    }
    }
    }

    string str1 = sb.ToString();

    using (StreamWriter fp = new StreamWriter(FileName))
    {
    fp.Write(str1);
    }

    }

  • Anonymous
    May 09, 2006
    PingBack from http://ase.jku.at/wordpress/?p=16

  • Anonymous
    July 27, 2006
    This is very informative.

    BTW, if I have a .NET module loaded into my GAC and if I need to get its File and assembly Versions, how to go about it using a simple query program?

  • Anonymous
    October 10, 2006
    This Blog contains some excellent information regarding versioning.  However, I have a question regarding versioning as it relates to internally developed .NET plug-ins.  Is there a standard practice for versioning plug-ins as they relate to the application(s) that they will ultimately be plugged into?  If I have a framework application product that contains essential or basic functionality, and then I develop plug-ins that may be added at the user's discretion, should the plug-ins be versioned independent of the framework product or should they be aligned with the product version?  I'm thinking they should be independent since they may also be used with another product?  

  • Anonymous
    February 28, 2007
    I have a strong named, signed assembly say abc.dll which I have deployed in GAC during product deployment. This assembly is being dynamically loaded using Assembly.Load method in different parts of the application and in different processes. I use the assembly's fully qualified name to load it. Now, this assembly will be updated as part of a service pack or a sandbox. By updating I mean replacement of the existing assembly. I want to know how the versioning of these assemblies should be done? Also, if the assembly versions (revision numbers) are changed in service packs, do I need to read the version number of assembly from some config file or will the same code, with the original version number will do? E.g. Initial Deployment abc.dll Version 1.0.0.1 Service Pack abc.dll Version 1.0.0.2 will the code Assembly.Load("abc, Version=1.0.0.1, ..."); work? or do I need to use? Version ver = /*Read from Config File */ Assembly.Load("abc, Version=<ver>, ..."); Thanks

  • Anonymous
    April 12, 2007
    I hesitate to talk about this because I don't want people who don't know about it to think, "Hey, what's

  • Anonymous
    April 12, 2007
    So, after checking out the binding context options , you've decided to switch your app to use the Load

  • Anonymous
    September 06, 2007
    Any latest Aseembly Versioning concept in .Net 2.0 version?

  • Anonymous
    March 26, 2008
    The comment has been removed

  • Anonymous
    March 10, 2009
    Hi Suzanne, <br><br> I include a link to a shared assemblyinfo.vb file for central versioning, but find that when I update the version - often the assembly version isn't updated in the compiled assembly. In other words, it stays the same when it should have changed. <br><br> I have taken to changing the version to a radically different one than the one I need (which may contain only a small increment), rebuilding - sometimes twice before the change is recognized, then changing to the version I need and rebuilding again. <br><br> This works, but is a flakey and time consuming work around when rebuilding a lot of projects. <br><br> Do you know why this happens and how to force each project to update to a specified assembly version (from a linked assemblyinfo.vb file) with a single rebuild? <br><br> yours curiously, <br><br> Ben

  • Anonymous
    July 08, 2009
    When I look in the GAC I see MS naming assemblies with the verison number as part of the name. Examples include: Microsoft.Office.Tools.Excel.v9.0 Microsoft.VisualStudio.Shell.Interop.8.0 Microsoft.VisualStudio.Shell.Interop.9.0 Microsoft.Build.Utilities.v3.5 Can you please comment on this.