Installing an assembly to the GAC and the local file system

Some products require that assemblies be installed to both the global assembly cache (GAC) and to the local file system. Windows Installer has native functionality that allows a setup author to do both. You can author an assembly as a global assembly (which will cause Windows Installer to install the file to the GAC) by adding it to the MsiAssembly and the MsiAssemblyName tables of the MSI and setting the File_Application column of the MsiAssembly table to Null. You can author an assembly as a private assembly (which will cause Windows Installer to install the file to the local file system) by adding it to the MsiAssembly table and setting the File_Application column to a file entry from the File table of the MSI. Windows Installer will take the file entry, look up the component that owns it and then use the directory entry associated with that component to install the private assembly to that same directory.

One of the first questions that comes up when a setup developer is trying to install an assembly to multiple locations is how to author the data in the MSI to install the same assembly component to both the GAC and the local file system. In most cases where a setup needs to install the same file to multiple locations, you can use the DuplicateFile table. Unfortunately, the DuplicateFile table does not support installing an assembly as both a global and a private assembly. In other words, you have the option to indicate that an assembly is a private assembly or a global assembly, but not both. In order to install the assembly to both the GAC and the local file system, you will have to create a second component and author one component as a global assembly and the other component as a private assembly.

We have to install assemblies to both locations as part of the .NET Framework and Visual Studio setups. In the case of the .NET Framework, the underlying architecture requires that the assemblies that are part it be installed to the GAC (for 3rd party applications) and to the local file system (for design-time scenarios in Visual Studio). However, we had to carry 2 copies of each assembly in the setup package in order to install to both places because Windows Installer doesn't support using the DuplicateFile table to do this. Carrying 2 copies of each assembly caused the overall size of the .NET Framework 1.0 and 1.1 redistributable setup package to grow even larger than it already was. After looking at a lot of different options, we decided to implement a custom action solution in .NET Framework 2.0 that would manage the installation of assemblies to both the GAC and the local file system. This allowed us to only carry a single copy of each file in the setup package and reduce the overall size of the .NET Framework setup by about 5 megabytes. Of course, if you compare the size of dotnetfx.exe between versions 1.1 and 2.0 you won't see much of a difference. What ended up happening was that the size of the features added in .NET 2.0 roughly cancelled out the size of the assemblies that we were carrying duplicate copies of in .NET 1.1.