A friend of mine that worked with me on my previous work place talked to me the other day and asked me why we put all of our assemblies in the GAC. After all, it does make a bit of a mess during the installation and no one actually see the benefit of it since a lot of the .NET first hype was “X-Copy Installation” and the “End to DLL Hell”.

As it usually goes in these situations, the “End of DLL Hell” brought its own set of challenges to overcome, therefore, I’ve decide to dedicate this post to the GAC and explain what is it for and how and when to use it.

What is the GAC?
So, what is the GAC? It stands for Global Assembly Cache and has two major functions:

  1. Provides a place to put a few versions of the same assembly that will co-exist side by side.
  2. Provides a place where one can place the native image of an assembly so that it will save us the need to perform Just In Time compilation (JIT) on the fly the first time we call to a certain method in one of the objects in that assembly.

In the old days before .NET and COM people relied on the search path to strategically place DLLs so that the application will find them and load them. There was a certain order and logic to the search path and people usually tried to go with it. If you wanted to place a DLL that will be accessible to all without changing the PATH environment variable, you usually put it in the SYSTEM directory (and later in the SYSTEM32 directory).

This process usually caused the DLL Hell since the application relied on a correct PATH envrionment variable and if, for some reason, it was changed or the same DLL in a different version was in a place before your DLL, your application would load the wrong version and bad things would start the happen.
At best, you can’t see some bug fixes and a new functionality, at the worst case, your application just crashes and strange places (depending how the application is written).

After the old days, came what I’d like to call the “Middle ages” and the era of COM which relied a bit on the search path as in the old days, but now it was written in the registry where to actually look for the exact DLL. If it couldn’t find it, it would rollback to the old days and usea the PATH environment variable and the search logic to try and find the DLL.

In the .NET era the GAC first major function comes to our aid. No more multiple places to put DLLs. We now have a single place that can provide a place to all of the versions of our assemblies all together. We can specifically redirect application that are suppose to use a certain version of the assembly to a different one using policy files and if everything is indeed in the GAC we are no longer in the mercy of the dreaded search path (although, if we can’t find the assembly in the GAC, the loader will revert to the old search path ways, as explained in this post).

The second major function of the GAC is to host the native images of assemblies that were compiled using the NGEN tool. If you wish to read more about NGEN and when to use it I suggest this fine post from Jason Zander‘s blog.

How to use the GAC?
The first basic condition of putting an assembly into the GAC is to strongly sign it. How to sign an assembly is beyond the scope of this post (but I will write about it in a future post).

After the assembly is strongly signed, you simply drop it in the “Assembly” folder located under you Windows Home Directory\assembly (that’s where the GAC is actually stored).

That’s it.

When to use the GAC?
OK, so now that we know how to use the GAC and what it was meant for, when should you use it?

Well, the rule of thumb is this… If you have a shared component that is used in more than one application OR your application exposes some kind of an API that can be used by other, you should definitely put your assemblies in the GAC. After all, this is one of its major uses!

If you have a simple executable or a simple application that only uses the assemblies in its own directory there is no need in putting anything in the GAC.

Quite simple, isn’t it?

In the next post I’ll dig a bit more into the inner workings of the GAC so stay tuned!

  • Urs Eichmann

    I write many small applications (mostly Winforms) which all use the samme common 2 or 3 DLLs with library functions in it. For every application, I create an own directory in the Program Files folder and put the EXE and all the library DLLs into this directory. I know I “should” use the GAC to put these libraries in, but I never experienced a single disadvantage of not doing so. As opposed, there are a few advantages: I can truly use XCOPY deployment; All the files are in one place and can easily be deleted if no longer needed; it is very clear which DLLs in which versions will be used in the programs.

    Using the GAC just because it is “recommended” is not enough a reason IMHO. Your article didn’t explain the REAL advantage either. Perhaps somebody could enlighten me?

    Best regards,
    Urs

  • Urs,

    I have stated the exact reasons to use it in the article, but in your case you should consider a few other things.

    First, if you are deploying this application more than a few customers and you have a bug in one of the 2-3 shared libraries you have. If you’ll fix it, you’ll have to put it in more than one place.

    If these libraries were in the GAC you could have simply put a newer version of the assembly and put a policy file to redirect to the new version, that way in ONE step in ONE place all of your application would have benefited from this.

    Putting things in the GAC is simple. If you have an installer software that supports that its even simpler, but even if you don’t, its just a matter of running the gacutil.exe program.

    If you have further questions, you are more than welcome to write to me.

  • Urs Eichmann

    Eran, thanks for your quick response. In theory, this sounds compelling – putting the DLL with the corrected code into just one place. However, in practice, the following need to be considered:

    – If I have an error in one of the libarary DLLs, I have to test every single application with the new, corrected version anyway. I cannot just deliver the new version hoping that somehow it will work with each application out there. There might be older applications which rely on the faultiness of the routine and which would stop working (in fact am just dealing with such a case this morining – an ideal monday morning job 🙂

    – If I have to change every application’s policy file, that means I STILL have to touch every application, develop and deploy a new installer and so on.

    – For .NET 1.1 apps, we use a homegrown deployment app, which works similar to ClickOnce – it checks if all the DLLs are current before the app is run. If not, it simply copies the newer DLL from a file or web server. This application is very simple, it is essentially a wrappter around XCOPY /D. Using the GAC would complicate the whole process, as it would have to issue gacutil commands and also update the policy file. Complication is never good, since it sacrifies reliability.

    – For .NET 2 apps, we use ClickOnce. For the user and for the developer, it doesn’t matter if ClickOnce puts the new version in the GAC or into the app dir. BTW, does ClickOnce even handle putting DLLs in the GAC?

    – For a newbie developer, perhaps coming from the COM/VB world, and even more for an administrator, the whole concept of GAC, policy files and redirections is quite hard to understand. Administrators want to know WHICH FILE EXACTLY is needed by a program. If he sees 10 versions of the same file in the GAC and has to check all the policy files in order to find out which file is being used by which application, he goes berserk. Compare this to the simplicity of: Everything needed for this application is in exactly one place.

    – If you iterate this concept of putting updated DLLs into the GAC while leaving old versions there, after 2 or 3 years, you end up with a cluttered-up GAC with very old versions in it which are not being used anymore. They will have to be removed manually by the admin, but only after the checks carefully with all the policy files scattered around…

    sorry, but I still fail to see the advantages of the GAC.

    Best regards,
    Urs

  • I will try to answer your claims one point at a time in the same order you wrote them:

    – You cannot avoid QA, but you are correct, it might make it a bit easier to ship everything in its own package, but that truely depends on your deployment model, the amount of products that share the same code and other parameters.

    – Having the policy file is just what you need to NOT recompile your application. If you are using the built-in versioning of .NET assemblies, if the assembly’s version changed without a policy file your application will try to load that version only, not older and not newer. With a policy file you can overcome this WITHOUT recompiling your application. Of course, you can always put the policy file near the assembly itself, but that will only let you put the exact assembly you wish the policy file to direct to and it might limit you.

    – As I said, it seems that in your case, since you have this homegrown ClickOnce thingy you don’t need the GAC.

    – Regarding ClickOnce, I assume it does support putting things inside the GAC but I haven’t tested it or read enough about it. I’ll try to give you a more accurate answer about this later.

    – As I’ve said, everything in one place is great and all and for simple application that don’t expose APIs its great but if you have some more complex needs such as running things side-by-side (and not putting them in different directoies). If you application exposes APIs that other applications that you did not write are using, if you don’t use a policy and preferrably the GAC to put things in one place it may break.

    – If you have a policy you can delete the older versions, since the policy will handle the redirections of the previous versions so you don’t have to have more than 1 assembly and 1 policy file.

    To sum things up, as I see in your case (as much as I could see and understand 😉 ) your uses does not justify using the GAC so in your case using it would be an over kill. In other scenarios that are usually a bit more complex, using the GAC can make things easier (for applications expsing APIs, for side-by-side, for using policy files and for generating a native image to make the startup time faster).

    Hope its clearer now.

    Eran

  • Urs Eichmann

    Thanks Eran for your valuable comment. At least now I know that I didn’t do anything wrong or not the way intended with my “simple” apps.

    As a rule of thumb, I will remember “If my application exposes a public interface, I’ll use the GAC, otherwise, I don’t”. This finally makes sense.

    Best regards
    Urs