Unable to add reference to assemblies in GAC from VS
Recently someone asked me about an issue he was facing in being able to add reference to an assembly in GAC from Visual Studio. This is a question that somehow keeps coming back. If you search online you will surely get pointers on how to solve this. The typical way is to provide the path to where your specific assemblies are by adding a registry key pointing to it, or add it to the already known standard paths and you will start to see your assembly in the .NET tab of the Add Reference dialog. See more details here. VS picks up files found in this path also - C:\Program Files\Microsoft Visual Studio 9.0\Common7\IDE\PublicAssemblies.
Now if you are satisfied by this, you have really only addressed the symptoms, but not the root cause. What is still unanswered is why VS didn't allow you add assemblies from GAC in the first place and went about it in a roundabout way?
In my opinion, there are really two aspects to this. The first is more about the fact that GAC isn't really organized the way it is seen as! Hmm, sounds a bit philosophical. In case you aren't aware .NET comes along with a Windows shell extension called Shfusion.dll. This DLL is found in your framework install path (on my machine the path is C:\Windows\Microsoft.NET\Framework\v2.0.50727). The typical view that you see that lists the name, version, culture, public key token and processor architecture is a view managed by this shell extension. Incidentally if you didn't know which is GAC folder, it is c:\windows\assembly or you can just type assembly in start/run and view this folder.
I am surprised that people don't automatically realize this for the simple fact that in a window's folder, you can't have two files with the same name. We can store multiple assemblies in GAC which have same name, but different assembly version. This by itself should be sufficient to point out that the folder structure has to be different than what is seen.
So, if you remove the shell extension, you can see the true folder structure. There are registry values that you can tweak (set HKLM\Software\Microsoft\Fusion\DisableCacheViewer [DWORD] to 1), but I personally prefer the simpler option of unregistering the shfusion.dll. You can run regsvr32.exe with -u command line option to unregister shfusion.dll (something like regsvr32 -u C:\Windows\Microsoft.NET\Framework\v2.0.50727\shfusion.dll). After this if you view the GAC in your windows explorer you will see the real structure which looks something like below.
The framework assemblies and other assemblies in GAC actually reside inside of a sub directory called GAC_MSIL. Within this a folder is created by the name of the assembly and then another folder inside of that with the version number. So each version actually sits inside of a folder named by the version and hence you are able to copy as many files with the same names but different versions in GAC. BTW, if you want to view GAC, without even bothering to unregister the shfusion.dll, you can use the good old command prompt and navigate to C:\Windows\Assembly and view the directories, sub directories and the files in this folder.
When you want to add a reference to an assembly for VS to use, it needs to know the path so that it can access that and the compiler can also access the assembly during compilation. Since GAC's actual directory structure is hidden behind the shell extension, VS can't really show the actual folder structure. You may argue that one can write code to query the folders and sub folders and then display the assemblies, but this will be a significant overhead while showing the Add Reference dialog. An easier approach would be to just put the assemblies in some other known path and load from there and that's exactly what is done. Hence you will find two copies of all the framework assemblies. One set is in GAC and another is in C:\Windows\Microsoft.NET\Framework\v2.0.50727 (or C:\Program Files\Reference Assemblies\Microsoft\Framework for 3.0 and 3.5). Also as mentioned earlier, the registry settings allow you to configure your own path that VS uses to show the files.
The second aspect more deals with the purpose of GAC itself. You would surely be already aware that GAC is a place to put shared assemblies i.e. assemblies used by many applications are put here. We already saw how GAC allows you to place multiple versions of the assemblies as well. So what this mean? If you pay little attention to detail, you would realize that the idea of shared assemblies for applications really is to do with the run state of the application. What I am trying to say is that when an application is running, it may pick up assemblies from GAC along with those that are privately deployed. While this is dealing with runtime behavior, VS is really a developer tool and is more about design time and build process. Why should anyone be bothered about GAC at this time? All developers need is to be able to add reference to the appropriate assemblies and compile and build against them. The deployment will take care of ensuring that all required assemblies (private and shared) are appropriately deployed and it is at this time that the CLR will probe GAC if it can't find an assembly required by the application in the private probing path. Hence in my opinion, the question "I can't add reference to assemblies in GAC in VS" is really invalid, since you should not be doing it anyway.
Hope this helps. Any comments are most welcome.