Infosys Microsoft Alliance and Solutions blog

« How to write custom Main method for a WPF application? | Main | Windows 7 »

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.  

GAC.jpg

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.

Comments

Excellent Post Atul.
This issue was bugging me since 2 days. Your post cleared my doubts.

Nishant, glad it helped.

Wonderful Article

'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.'

ummm... I don't quite follow that statement. How does one develop software in VS withOUT adding references to asssemblies in GAC?!

... at least sometimes. For instance, I'm developing .NET code that uses the BizTalk Rules Engine. Explain to me how I would not have to add references to the BizTalk Rules Engine dll's that are in the GAC. Just as an example.

StillRockin, I don't have BizTalk installed on my machine anymore else, I would have given you the path, but typically the assemblies would be present in c:\program files\Microsoft BizTalk Server\. Like quite a few .net framework assemblies are also found in C:\Program Files\Reference Assemblies\Microsoft\Framework\v3.5.

I will state once again that GAC is for your runtime behavior and not development usage via VS.

Thanks for this very clear article it confirms my view on this issue.

In visual studio I add a reference by browsing to an own defined assembly folder where all my newest dll's are placed and select them.

After they have been selected I change the folder name, and Visual Studio will automatically change the library path by probing to the Gac and after that I deploy the web app. So .net don't need to do probing on runtime.

You actually can refer assembly from GAC. I didnt find anything from Visual Studio but here is some hack.

Add reference to the assembly by browsing to the folder.

Now close your visual studio solution and open the .csproj file using notepad.

remove hintpath from tag of the assembly.

reopen solution in visual studio.

it will resolve the assembly reference from GAC.

Hasan, i am sure there are ways to get around, but the question really is do I want to get around? I had addressed in the later part of the blog. Take another similar example - the private/protected accessors in C++ are more for compiler to check incorrect access. This only prevents accidental access issues by well meaning developers.

On similar lines, I feel that accessing GAC isn't something that anyone should try and do via VS for resolving reference at compile time. Assemblies should be located some place else for it and GAC should be treated as runtime environment, so that people also can get the benefit of versioning.

I understand that GAC is for runtime only and will be automatically included by CLR at runtime but then how someone can use those assemblies in the code without getting reference not found errors in VS.

Rajesh, Do you know of specific case? Reference is necessary to resolve compile time linkages. The only time it will not be necessary if you are using reflection to load assemblies at run time.

I am trying to implement cmdlet for System.Management.Automation since this assembly gets installed in GAC when you install PowerShell 1.0 so can you please show me how to use this assembly without reference in the VS?

Rajesh, when you install powershell, doesn't it also provides some of these assemblies in the install path? Like if working with say Silverlight, you will find assemblies in C:\Program Files\Microsoft Silverlight\3.0.40818.0 and this path can be used to add reference to VS.

If there is no such path where assemblies are additionally installed, then a hack I have used sometimes is to copy the assembly from GAC to another file folder and use that path. To copy, you can do this via command prompt using plain old DOS commands.

I have got this working but I am asking this incase if I was missing something. So "I can't add reference to assemblies in GAC in VS" is still a valid problem if you don't have a copy of the assembly in other location and we do need a work around for that. Correct?

Muse VSReferences will allow you to add a Global Assembly Cache reference to the project from Add GAC Reference menu item.

http://visualstudiogallery.msdn.microsoft.com/en-us/36a6eb45-a7b1-47c3-9e85-09f0aef6e879

@Muse VSExtensions, while this may work, the point that i mentioned earlier is that we need not really worry about it. GAC should be treated as a respository during runtime usage and not during design/compile time

Some vendors just install assemblies directly into the GAC, making it impossible for Visual Studio to reference them.


@Atul

However, there is way around this problem using http://visualstudiogallery.msdn.microsoft.com/en-us/36a6eb45-a7b1-47c3-9e85-09f0aef6e879 extension. Actually SharpDevelop has Add GAC Reference dialog

@Atul
May be it's too late to answer, but i found a very simple way to do this(without a hack).

1. Put your dll in GAC (for 3.5 Drag Drop inside "C:\Windows\assembly\")

2. GoTo Projects --> Properties

3.Click Reference Path (for 3.5 it's "C:\Windows\assembly\")

4. and Build

Hope it helps

Post a comment

(If you haven't left a comment here before, you may need to be approved by the site owner before your comment will appear. Until then, it won't appear on the entry. Thanks for waiting.)

Please key in the two words you see in the box to validate your identity as an authentic user and reduce spam.

Subscribe to this blog's feed

Follow us on

Blogger Profiles

Infosys on Twitter