Enabling in-place assembly upgrades using Windows Installer and WiX

Recently, I tried to create a Windows Installer major upgrade for an MSI that I was working on.  This MSI installs assemblies to the GAC and I did not want to change the assembly version for these assemblies in the new MSI.  As a result, I scheduled the RemoveExistingProducts action after the InstallFinalize action in order to avoid the issue described at https://support.microsoft.com/kb/905238.

However, after creating the new version of this MSI and running through a test major upgrade scenario, I found that the assemblies in the GAC were still the ones with the old file versions from the older version from the MSI.  When investigating this issue, I found the following information in the verbose MSI log that explained why the assemblies were not being updated in the GAC like I expected:

MSI (c) (34:24) [11:11:11:111]: skipping installation of assembly component: {A84F2D22-3442-4121-838B-97805DBE8FE7} since the assembly already exists

I was not sure how to fix this, so I asked Heath Stewart for help, and the first thing he asked me to do was look in the MsiAssemblyName table of the new version of my MSI and see what attributes are listed there for each assembly.  When I did that, I found that each assembly had attributes for name, version, culture, publicKeyToken and processorArchitecture.  Heath pointed out to me that what I am trying to do in this scenario is an in-place update of an assembly in the GAC - meaning that the assembly has the same strong name but a different file version.  Windows Installer will not perform an in-place update of an assembly in the GAC unless the fileVersion attribute is set for the assembly in the MsiAssemblyName table of the new MSI.

Now that I knew why these assemblies were not being updated, I had to figure out why the fileVersion attribute was not being included in the MsiAssemblyName table of my MSI and then find a way to add it.  I am using WiX v3.0 to create these MSIs, and I discovered that by default, WiX does not include the fileVersion attribute in the MsiAssemblyName table when it creates MSIs.

It is possible to override the default behavior.  Doing either of the following will cause WiX to include the fileVersion attribute for all assemblies in the MsiAssemblyName table of the MSI:

  1. If you are building your MSI by calling the WiX tools directly, you can add the -fv switch when calling light.exe (the WiX linker)
  2. If you are building your MSI by using Votive in the Visual Studio IDE or by running MSBuild and passing in a .wixproj file, you can add the following parameter to your .wixproj file:

<SetMsiAssemblyNameFileVersion>True</SetMsiAssemblyNameFileVersion>

After using one of the above options, I rebuilt my MSI and verified that it now contains the fileVersion attribute for each assembly in the MsiAssemblyName table.  Afterwards, I tried a new test of the major upgrade scenario I was working on and found that the assemblies in the GAC were now updated to the new file version as I expected.

For reference, you can find more information about how Windows Installer updates assemblies in this MSDN topic.