Monday 8 February 2010

Where is the Global Assembly Cache?

Introduction

When I first came across the Global Assembly Cache (GAC), back in the days of .NET 1.1, my first thoughts were: "But what is it? And where is it?". Even if I lookup its official definition now, all I get is:

A machine-wide code cache that stores assemblies specifically installed to be shared by many applications on the computer. Applications deployed in the global assembly cache must have a strong name. See also: assembly cache, strong name.

Looking up assembly cache in the same list of definitions gives:

A code cache used for side-by-side storage of assemblies. There are two parts to the cache: the global assembly cache contains assemblies that are explicitly installed to be shared among many applications on the computer; the download cache stores code downloaded from Internet or intranet sites, isolated to the application that caused the download so that code downloaded on behalf of one application or page does not impact other applications. See also: global assembly cache.

I don't like vagueness. Are the assemblies stored in a database? As binary objects within the registry? As files on the file system? Where?

I decided to find out the answer. It wasn't hard. But every time I mention it to people they seem surprised. So I thought quickly document it here.

Assembly Cache Viewer

You probably already know that you can view the GAC via the .NET Framework Configuration MMC snap-in and within Windows Explorer by browsing to %SystemRoot%\assembly. When you do the latter it's clear that you're not looking directly at the file system as the columns presented don't match anything you would expect to see when viewing a 'normal' folder:

Global Assembly Cache

This representation of the GAC is being provided by the Assembly Cache Viewer (implemented in Shfusion.dll), which is a Windows shell extension.

Accessing the GAC via a Command Prompt

Wouldn't it be interesting to see what the contents of %SystemRoot%\assembly really looked like? Try doing a "DIR %SystemRoot%\assembly" from a Command Prompt window. You'll see something like this:

 Volume in drive C has no label.
 Volume Serial Number is 90E6-F9FC

 Directory of C:\Windows\assembly

06/09/2009  19:26    <DIR>          GAC
13/12/2009  19:01    <DIR>          GAC_32
09/01/2010  19:01    <DIR>          GAC_MSIL
11/05/2009  14:15    <DIR>          NativeImages1_v2.0.50727
01/12/2009  16:46    <DIR>          NativeImages_v2.0.50727_32
13/12/2009  19:01    <DIR>          temp
09/01/2010  19:01    <DIR>          tmp
               0 File(s)              0 bytes
               7 Dir(s)  22,497,624,064 bytes free

That's interesting: there's a folder named GAC. Actually, there are three: GAC, GAC_32 and GAC_MSIL. These logically map to the values for Processor Architecture in the screenshot above of blank, x86 or MSIL respectively.

So, using the screenshot above, I'd expect to find Accessibility within the GAC_MSIL folder. Let's try a "DIR %SystemRoot%\assembly\GAC_MSIL":

 Volume in drive C has no label.
 Volume Serial Number is 90E6-F9FC

 Directory of C:\Windows\assembly\GAC_MSIL

09/01/2010  19:01    <DIR>          .
09/01/2010  19:01    <DIR>          ..
02/11/2006  11:18    <DIR>          Accessibility
02/11/2006  11:18    <DIR>          AspNetMMCExt
02/11/2006  12:35    <DIR>          ComSvcConfig
29/04/2009  23:21    <DIR>          CppCodeProvider
29/04/2009  23:21    <DIR>          CRVsPackageLib
29/04/2009  23:21    <DIR>          CrystalDecisions.CrystalReports.Design
29/04/2009  23:21    <DIR>          CrystalDecisions.CrystalReports.Engine
29/04/2009  23:21    <DIR>          CrystalDecisions.Data.AdoDotNetInterop
29/04/2009  23:21    <DIR>          CrystalDecisions.KeyCode
29/04/2009  23:21    <DIR>          CrystalDecisions.ReportAppServer.ClientDoc
29/04/2009  23:21    <DIR>          CrystalDecisions.ReportAppServer.CommLayer
etc.

Yup. Accessibility is certainly there. But it's a folder. We were expecting an assembly. Let's take a peek inside with "DIR %SystemRoot%\assembly\GAC_MSIL\Accessibility"

 Volume in drive C has no label.
 Volume Serial Number is 90E6-F9FC

 Directory of C:\Windows\assembly\GAC_MSIL\Accessibility

02/11/2006  11:18    <DIR>          .
02/11/2006  11:18    <DIR>          ..
30/04/2009  20:51    <DIR>          2.0.0.0__b03f5f7f11d50a3a
               0 File(s)              0 bytes
               3 Dir(s)  22,490,701,824 bytes free

Hmmmm. Another folder. It's name looks interesting though. It seems to be comprised of a version number and a public key token. But why two underscores in between? A quick glance as the listing from Windows Explorer suggests that the format is almost certainly Version_Culture_PublicKeyToken.

So what's inside this folder? Lets run a "DIR %SystemRoot%\assembly\GAC_MSIL\Accessibility\2.0.0.0__b03f5f7f11d50a3a"

 Volume in drive C has no label.
 Volume Serial Number is 90E6-F9FC

 Directory of C:\Windows\assembly\GAC_MSIL\Accessibility\2.0.0.0__b03f5f7f11d50a
3a

30/04/2009  20:51    <DIR>          .
30/04/2009  20:51    <DIR>          ..
27/07/2008  18:03            10,752 Accessibility.dll
               1 File(s)         10,752 bytes
               2 Dir(s)  22,490,607,616 bytes free

Aha! There's the assembly itself. Feel free to wander through this directory structure on your own and confirm that this layout holds true for you.

So, when you use GACUTIL to install an assembly into the GAC, what you're actually doing is copying it to the %SystemRoot%\assembly\GAC_ProcessorArchitecture\AssemblyName\Version_Culture_PublicKeyToken folder.

A Final Word of Caution

Of course, Microsoft are perfectly within their rights to change the GAC's implementation whenever they like. But knowing how assemblies are actually stored in the GAC can certainly help in certain situations. For example, suppose you need to compare a UAT and a Production server to confirm that the same versions of all your third-party controls are installed in the GAC. All you need do it issue the relevant DIR commands on both servers and compare the outputs. Simple. If some are missing from one box, just XCOPY them across from the other. This sounds mad, I know. It seems like GACUTIL must surely be doing more than just copying the files. I'm sure it is. It's checking they have a valid strong name for a start. But I've used the XCOPY technique to deploy assemblies from the GAC on one machine to the GAC on another and it works just fine.

See Also

No comments:

Post a Comment