|
|||||||||||||||||||||
|
|||||||||||||||||||||
|
Announcements
Want a new Job?
Chapters
Services
Feature Zones
|
IntroductionMy first introduction to the .NET Global Assembly Cache (henceforth referred
to only as the GAC) was during a Guerrilla .NET Course conducted by Develop
Mentor a week after the .NET Framework Beta 1 Release. I was immediately
fascinated by this magical and mysterious piece within the entire .NET puzzle
(yes, .NET had been a puzzle to me for a very long time). While ordinary
( The primary purpose behind writing this article is to share my findings related to the GAC with the development community. The information presented herein is original and a direct result of my personal research. To the best of my knowledge, these details have not been covered in any .NET article or book. Since references to Fusion occur throughout this article, it
may be appropriate to clarify the significance of this name vis-à-vis the GAC.
Fusion is the internal name of the project at Microsoft to eliminate the
problems of sharing DLL code. The GAC was originally called the Fusion
cache and is currently implemented within CreditsI would like to thank Vince Henderson (Software Design Engineer/Test Lead), Sameer Bhangar (Software Design Engineer/Test) and Alan Shi (Software Design Engineer) from the Microsoft .NET Team for patiently answering my questions while I was researching the material for this article as well as for providing valuable suggestions after reviewing the first draft. DisclaimersConsidering the Under-The-Hood nature of details covered in some sections of this article, appropriate cautionary notes have been placed immediately preceding such information. It will be prudent to heed these warnings and if you disregard these cautionary notes, it will be at your own risk. The BasicsFor the benefit of those that are genuinely unaware of what the GAC is, I am providing this simple description which has been plagiarized from the online documentation: Each computer wherein the common language runtime is installed has a machine-wide code cache called the Global Assembly Cache. This Global Assembly Cache stores .NET assemblies specifically designated to be shared by several applications on that computer. As a general rule, the Windows Registry is considered legacy within .NET and XCOPY deployment is highly encouraged, which in turn implies building assemblies that are private to a program’s main executable. Yet, there is a definite need for a central repository for .NET System assemblies as well as other user created Shared assemblies and it is this very need which is addressed by the GAC. Refer to .NET Framework Developer’s Guide: Global Assembly Cache for the formal product documentation on this topic. The Microsoft KB article Q315682 HOW TO: Install an Assembly into the Global Assembly Cache in Visual Studio .NET walks the uninitiated through the steps required to install a .NET assembly into the GAC. If it is not already obvious, a key point to note here is that once your application installs Assemblies in the GAC, it loses the benefits of XCOPY deployment as these assemblies (other than the .NET System Libraries) must be explicitly installed in the GAC. While covering the basics, it is important to understand the concept of Identity as it pertains to a .NET Assembly. An Assembly’s identity includes its simple textual name, a version number, an optional culture if the assembly contains localized resources, and an optional public key used to guarantee name uniqueness and to protect the name from unwanted reuse (name spoofing). An assembly with a simple Identity includes just the mandatory simple textual name and version number components. Since the GAC is the machine-wide repository for shared assemblies, it is very easy to run into the problem of name collisions if these assemblies only had simple identities because they are developed independently by different vendors and even developers within your own organization. Hence it is mandatory that every shared assembly installed in the GAC have a Strong Name. The formal definition of the term in the online documentation is A strong name consists of the assembly's identity — its simple text name, version number, and culture information (if provided) — plus a public key and a digital signature. It is generated from an assembly file (the file that contains the assembly manifest, which in turn contains the names and hashes of all the files that make up the assembly), using the corresponding private key. Refer to Strong-Named Assemblies and Creating and Using Strongly-named assemblies for the details around strongly-named assemblies. Of particular interest within the first URL are the three bullets that describe the requirements satisfied by strong names as well as the last paragraph that describes why a strong-named assembly can only reference other strong-named assemblies. Popular misconceptionsOne popular misconception is that strongly-named assemblies must always be
installed in the GAC. Strongly-named assemblies can be put in the GAC, but by
no-means have to be put there. It is desirable to put strongly-named assemblies
under the application directory if you want to ensure your application has no
system-wide impact, and make sure that it can be Another popular misconception is that assemblies must be installed in the GAC to make them accessible to COM Interop or unmanaged code. Neither of these scenarios mandates installing assemblies in the GAC and as a general guideline, you should install assemblies in the GAC only if they must be shared with other applications on the same machine. Contrary to popular belief, it is not possible to directly reference an assembly from the GAC within a Visual Studio.NET project. In simpler terms, the assemblies listed within the .NET tab of the Add Reference dialog box for both Visual Studio.NET 2002 and 2003 are not enumerated from the GAC as this dialog box is path based. Refer to the More Information section of Microsoft KB article titled INFO: How to Display an Assembly in the Add Reference Dialog Box for a workaround to this very common issue faced by .NET developers. The Public and not so public faces of the GACIn order for the GAC to be useful, we need to be able to interact with it. I am aware of the following five interfaces available for such interaction.
Each of these is explored in detail within the following sections. The GAC itself is implemented as a hierarchy of directories. When using these interfaces to interact with the GAC, we are isolated from the implementation details of the GAC (which by-the-way is a good thing). The default ACLs inherited from the 1. The Windows Installer 2.0Developers of Windows Installer packages can install assemblies to the GAC using Microsoft Windows Installer 2.0. This is the preferred way for installing such shared assemblies and should be the only way shared assemblies are installed on non development machines. The main benefits of using the Windows Installer 2.0 for installing assemblies to the GAC are:
Some starting references within the .NET and Visual Studio.NET documentation around Windows Installer 2.0 are as follows:
2. The command line tool GACUtil.exeThis command line tool allows you to install assemblies to the GAC, remove them from the GAC and list the contents of the GAC. The online documentation for this tool is available at Global Assembly Cache Tool (Gacutil.exe). To install an assembly called MyAssembly in the GAC, you use the command gacutil /i MyAssembly.dll To remove this assembly from the GAC, you use the command gacutil /u MyAssembly To view the contents of the GAC, you use the command gacutil /l Note that when uninstalling, we use just the simple textual name of the assembly since for strong-named assemblies installed in the GAC, its simple textual name matches the DLL name. Using the You should avoid using
3. The Windows Shell namespace extension implemented in SHFusion.dllSince a picture is worth a thousand words, I am including this image of the
GAC as seen through the Windows Explorer when the Shell Extension
The complete documentation for this Shell Extension is available at Assembly Cache Viewer (SHFusion.dll). When the c:\windows\assembly directory is selected (clicked on), the right
hand pane displays each and every assembly installed in the GAC along with
additional information like Type, Version, Culture and Public Key Token. An
assembly displayed with a Type of Native Images essentially means
that an NGEN.exe generated native image is available for that
assembly. Notice also that for every such assembly, there is a corresponding
MSIL assembly e.g. Selecting ‘Properties’ from the right-click menu displays the following properties window:
Most of this information is self evident but a couple of properties may need additional clarification. ReferencesThis is not a very useful field and may well be removed in the next release
of the .NET Framework. The basic problem is that the GAC implementation only
gets a Yes / No answer from MSI on whether it has a reference to an assembly in
the GAC but not an exact count of how many references MSI holds to the assembly
(e.g. MSI could have 10 references and it'll still show up as only one
reference). Additionally, the GAC implementation knows about its own traced
references ( To view reference info CodeBaseThis property displays the path of origin for the assembly. It is for
informational purposes only and cannot be relied on to be available always. When
assemblies are installed through MSI, there's no codebase available for
that shared assembly since the bits are streamed in from the MSI package and
hence the field will display as blank. Basically, codebase is available
only when a shared assembly is installed using a file path (e.g
The value of this property should be clear when you consider that the display name for two different assemblies can be the same, say Microsoft’s System and Widgets’ System. Strong names make this a real possibility and the path of origin can help make clear to the user which assembly is being referred to whereas the different public key tokens would not. It is also important to point out that there is no mechanism to try to recover / restore files from this path of origin a la Windows File Protection or the Auto-Repair option supported by Windows Installer 2.0. Disabling the Assembly Cache ViewerWARNING: The following steps involve modifying the Windows Registry. If you use Registry Editor incorrectly, you may cause serious problems that may require you to reinstall your operating system. The author as well as Microsoft cannot guarantee that you can solve problems that result from using Registry Editor incorrectly. Use Registry Editor at your own risk. If you want to disable the Assembly Cache Viewer and see the GAC in all its
naked glory within Windows Explorer, you can set
4. The .NET Framework Configuration Administrative toolThe Microsoft .NET Framework Configuration MMC snap-in is accessible through Start | Control Panel | Administrative Tools. When you first click on the Assembly node under My Computer the following screen is displayed:
View List of Assemblies in the Assembly Cache Upon selecting this task, the right pane displays the list of installed assemblies, similar to the view provided by the Assembly Cache Viewer.
The Action pull down menu includes the Copy, Delete, Properties and Help menu items, all of which are self explanatory. The properties window displays only the General tab. When compared to the properties window displayed by the Assembly Cache Viewer, the References property is missing while an additional Cache type property is displayed. The View pull down menu includes the Add/Remove Columns, Help Topics and Refresh assembly list menu items. The Help Topic menu item switches to the view displayed when you first click on the Assembly Cache node. Add an Assembly to the Assembly Cache Upon selecting this task the following dialog box is displayed which enables an assembly to be installed into the GAC.
5. Programmatically accessing the GAC through APIsCAUTION: Do not use these APIs in your application to perform assembly binds or to test for the presence of assemblies or other run time, development, or design-time operations. Only administrative tools and setup programs must use these APIs. If you use the GAC, this directly exposes your application to assembly binding fragility or may cause your application to work improperly on future versions of the .NET Framework. While the previous four options for interacting with the GAC are useful, there are occasions when we may be forced to use a programmatic way to interact with the GAC through our own code. The developers that implemented the GAC have already accounted for this and there is a full fledged API that is available for this very purpose. The Microsoft KB Article Q317540 Global Assembly Cache (GAC) APIs Are Not documented in the .NET Framework Software Development Kit (SDK) Documentation formally documents this API, so there is no reason for me to rehash the information within this section. It will be prudent to heed the cautionary note at the beginning of the KB article which has been reproduced in this article. Relocating the GACThe default location of the GAC is under the WARNING: The following steps involve modifying the Windows Registry. If you use Registry Editor incorrectly, you may cause serious problems that may require you to reinstall your operating system. The author as well as Microsoft cannot guarantee that you can solve problems that result from using Registry Editor incorrectly. Use Registry Editor at your own risk.
As an example, if you want to move the GAC on your machine from the default
A few points worth noting regarding the GAC relocation process are as follows:
When I first tried to move the GAC to another location, I noticed that the
Shell Namespace Extension Once the initial euphoria after learning this technique has subsided, the logical question one would ask is why would anyone ever want to do this in real life? Initially, I flirted with the idea of using this feature to have the GAC installed on a File Share (e.g. a Network Access Storage device) and reference that location from other machines that require the same set of shared assemblies. This way, the GAC would not occupy hard disk space on each machine within the cluster / group. Additionally, I would be able to install shared assemblies from one machine and have these available to .NET applications running on all other machines in that cluster / group. Given my somewhat decent understanding of .NET Security (and without a lot of time available to experiment with this configuration), I quickly came to the conclusion that such a configuration would be impractical given the fact that the system assemblies themselves will be executed under the LocalIntranet Permission Set, leading to unpredictable behaviour. I am also sure that Microsoft Product Support considers this an unsupported configuration. All the same, I do feel that this would be a nice option to have as I have seen the size of the GAC bloat dramatically over time and a central location for a cluster of servers will be conducive to disk space as well as administration. So the only good reason I can think of for now is to relocate the GAC to a different Windows drive (C: D: etc.) in case space becomes tight on the hard disk partition on which the GAC was initially installed. This is certainly possible given the amount of additional disk space that side-by-side installation of the .NET Framework and third party shared assemblies utilize. Application Center 2000 Replication Support for .NET GACApplication Center 2000 (AC2000) Replication feature ensures that specified files and directories are kept in sync across servers in a cluster. If such a file or directory is accidentally (or maliciously) deleted / overwritten, AC2000 Replication will ensure that the original is immediately replicated on that server (adding an event log entry to indicate the operation it performed). Prior to the release of AC2000 SP2, GAC assembly replication support was made available as a separate download for AC2000 installed on servers running the Windows 2000 O/S. Microsoft KB article Q396250 INFO: Application Center 2000 GAC Replication Support for Windows 2000 has all the details regarding this interim support package. With the release of AC2000 SP2, the temporary version of the GAC assembly replication is no longer relevant (unless there is some kind of exception granted by Microsoft Support Services that allows a server installation to continue running AC2000 SP1). Installing AC2000 SP2 on servers running the Windows 2000 O/S wherein the temporary version of the GAC assembly replication has been previously installed will automatically replace it with the final version. AC2000 SP2 is the first service pack that supports Application Center on servers running Windows Server 2003 and installing SP2 on these servers will always install the final version of the GAC assembly replication feature. Exploring the current implementation of the GACWARNING: The GAC details which are described within this section are relevant only to the implementation as observed in the Microsoft .NET Framework 1.0 and 1.1 releases. Subsequent releases of the .NET Framework may result in changes to or even a complete overhaul of today’s implementation. Any reliance on the implementation details described herein is strongly discouraged and should be used at your own risk. Additionally, using MS DOS commands to alter or delete these internal folders or contents of files therein may lead to unpredictable behavior or other serious problems that may require you to reinstall the .NET Framework on the affected machine(s). Use such commands at your own risk. As we know from a previous section, the default location of the GAC is under
the
The Dir command displays four separate directories which are briefly described here. GAC: The container for all the MSIL assemblies installed within the GAC. NativeImages1_v1.0.3705: The native images generated for .NET Framework 1.0. Temp and Tmp : These are temporary staging directories that are used by the current implementation. The Exploring further into the GAC folder reveals folders named after each of the assemblies installed in the GAC.
Progressively drilling through this hierarchy of folders reveals the organization of the GAC and how it implements Side-By-Side installation.
Within each folder for a shared assembly, there is a sub folder named using
the version and public key token components of the assembly e.g.
Notice the The URL is the same as the Path of Origin displayed as the CodeBase property
displayed within the Properties dialog displayed by
What happens if a directory is accidentally deleted?Since there is no Windows File Protection for GAC assemblies, it is important to reiterate what has been covered in previous sections of this article. If one accidentally deletes a folder within the GAC folder hierarchy, ONLY assemblies that are installed using MSI will be reinstalled at runtime if they are not found in the GAC. Since the .NET Framework is installed using MSI, all the System.* assemblies are considered safe from accidental or malicious tampering (provided the .NET Runtime MSI is accessible). SummaryDuring the course of this article, we have explored the .NET GAC in sufficient detail. It is my sincere hope that the reader has learned something new in the process and will find some of this information useful when working with .NET on a day to day basis. I am always open to suggestions for improvement and hence will appreciate healthy criticism related to the material presented here. History
| ||||||||||||||||||||