Share via


GAC Phobia

I was recently forwarded a link to a posting entitled “Avoid the GAC”. I would like to offer some insights into points addressed by this article, to help clarify misconceptions you may have about the GAC, and its intended usage.

The article argues that the GAC is the managed equivalent of the Windows system32 directory, and suffers from the same DLL sharing problems of the past (e.g. “DLL hell”). While it is pointed out that the GAC does facilitate side-by-side storage of DLLs based on the assembly’s strong identity (something that did not exist with system32), the author reasons that side-by-side storage isn’t useful because if a new version is available that your app didn’t use, then the update was pointless. Publisher policy is mentioned as a way to force all apps to use the update, and the argument concludes by saying that this ends up in exactly the same place we started with—system32.

A large source of confusion in this topic stems from what publisher policy really is and what it is intended for. There are two very different scenarios for updating an existing assembly:

1) Critical service updates (e.g. security fixes). These are tactical fixes intended to address specific problems with some previously released version of the component. No new features are in the update, and it is expected that the code is highly compatible with the existing version.

2) New feature releases. It may be the case that the new code is mostly compatible with the old version of the assembly, but there are no guarantees.

In case (1), it is clearly desirable to affect all applications on the machine. Because of the critical nature of security fixes, users (and administrators) want to be assured that if they apply a given security fix, that all applications are patched. This is a far better story than trying to hunt down n different applications on the machine that may be using the buggy component, and patching them individually. In the post-slammer-virus world, it should be evident that central servicing for security updates is a critical piece of ensuring machines are protected against malicious code.

In case (2), we recommend that component authors do not ship publisher policy statements which affect all applications. Because the compatibility of the assembly cannot be guaranteed against older versions, consuming the update should be done on an opt-in basis, rather than by default. You can selectively choose to use a new update for a particular application by utilizing application configuration policy.

To be clear, I am not advocating putting everything in the GAC. In fact, there was a fair amount of work put into supporting the xcopy deployment model, because of its simplicity and ease of use. An xcopied application is generally easier to move from machine to machine; there’s no complex setup necessary to install such an application.

If a publisher policy assembly containing a critical security fix is installed onto a given machine, it will affect all applications that use the older version of the assembly regardless of whether or not that assembly was xcopy deployed or installed into the GAC. But where does the assembly with the actual fixed bits go? The policy will affect every application that used the old version, and clearly there needs to be a place where those applications can find the fixed bits. The GAC is the natural choice here.

These two scenarios are somewhat confused in the “avoid the GAC” article. The author claims that there is no point in providing a new version if it is not intended to affect all applications—it may as well not be side-by-side. This is not true. As mentioned above, for security fixes, it is definitely desirable to affect all applications. Even so, this does not imply that security fixes should not be side-by-side. Inevitably, there will be cases where a critical security fix will break some application, and users/administrators will need to revert to the old functionality. Side-by-side helps you here, because it allows you to selectively roll back a given application to use the older version, while still allowing all other applications to use the fixed bits. This is a conscious decision by the user/administrator to bypass the security fix because this is an exceptional circumstance.

For non-security fixes, policy should not be applied to maintain maximum application compatibility. This, however, does not mean that one should avoid the GAC; these points are orthogonal. The GAC is designed to store multiple versions of the same component simultaneously. Two different functional/feature versions can happily live side-by-side without interfering with each other. Critical service updates can also live side-by-side with the pre-serviced version, in order to allow selective rollback where necessary.

A final point I would like to mention is that although disk space certainly is cheap in today’s world, sharing assemblies in a single location is still a very commonly requested feature. Sharing the same physical disk space location allows other optimizations, such as reduced memory pressure from not having to load the same copy of the DLL from many different locations (I will resist the urge to dive into related topics like domain neutrality and native images).

In summary, the old problems of “DLL hell” via DLL-name thrashing in system32 do not exist for the GAC. In the world of side-by-side, there are new considerations of how and when to update a component. While xcopy is definitely an attractive way to deploy your application/assembly, it is not the only way to do so, and there are legitimate reasons to make your component globally visible on the machine. Side-by-side allows users to selectively roll back applications which policy may have redirected forward.

Comments

  • Anonymous
    March 28, 2004
    I think that the subject of the GAC and it's correct use... also the use of Strong Names is very mis-understood and could use a lot of work.

    some folks for example are confused into thinking that a "strong Name" can provide some stong "copy protection" and complain when they find that the strong name can be removed ... disasembled il and re-compile etc...

    I suspect that some folks are "shoting them selves in the foot" with thier lack of understanding of the gac and SN....

  • Anonymous
    March 28, 2004
    The comment has been removed

  • Anonymous
    March 28, 2004
    The problem with forcing apps to use a "critical update" version of an assembly is that sometimes the app relies on the broken behavior. You'll break it if you fix your assembly (can anybody say WinNT SP4 with fixed memory management?). But there's really not much that can be done, maybe symbolic links to shared code each app is using (so you can point different apps to different assemblies and update them to newer versions independently) would do.

  • Anonymous
    March 28, 2004
    The comment has been removed

  • Anonymous
    March 28, 2004
    The comment has been removed

  • Anonymous
    March 29, 2004
    I agree 100% with whatever Dag said. When people break out the umlauts, you know they mean business.

  • Anonymous
    March 29, 2004
    Det finns många åsikter om GAC:en, vad skall installeras där och hur skall uppdateringar ske, är några av de vanliga frågorna. Alan Shi, skriver ett intressant inlägg, som ett svar på en person som inte rekommendar GAC:en till speciellt mycket,

  • Anonymous
    March 29, 2004
    Since .Net apps copy refrenced assemblies to it's local directory, we decided to place our assemblies in the GAC. We felt that if we did it that way we could update the GAC with our new assemblies and the .Net applications could pickup the new assemblies. Sounds good so far...

    It gets more complicated by the fact that we can't just put our assembly in the GAC, all it's dependencies must go there as well. Now we have 7 assemblies in the GAC. Say we need to patch one for a fuctional fix, now I have a few options, they all assume that I want everything to use the new assembly. (I'm of Sells mind, why would I release a patch if I don't want it used? It should be tested for backwards compatibility anyway.)

    1) Add the fixed assembly to the GAC as well as a ton of publisher policy files.
    2) Release a new set of all the assemblies that go in the GAC even though only one has changed.

    This stuff is on top of all the dev headaches. With all these problems and issues to tackle, it's hard to imagine that this all came from wanting to update all my clients like COM already did for me when I just registered the new version. In the end I hope to pull everything out of the GAC and have my install hunt down all the my clients itself and update them.

    I'VE GOT GAC PHOBIA! :)
    Peter Thomas

  • Anonymous
    March 29, 2004
    Peter,

    What factors are forcing you to update the shared assemblies independantly of the applications which are using them?

    Thanks,
    Maurice

  • Anonymous
    April 01, 2004
    The comment has been removed

  • Anonymous
    April 02, 2004
    The comment has been removed

  • Anonymous
    April 05, 2004
    Alan,
    I would agree that what I'm, and many other people, are doing doesn't follow MS's recommended policy for GAC use.

    The problem is, I used to live in the simple COM world where I could update one file and all its clients would use the new file. With .Net we have lost this ability. The closest we can get to it is our "misuse" of the GAC.

    Now I know what you’re thinking. You've already said it: "Making a new version of an assembly that has functionality upgrades and forcing all apps to use the new version is a recipe for breaking apps". Your point being that the assembly authors can't assume that they won't break all the client apps so let the client chose when/if to use the updated assembly. I don't know about other people but our company develops enterprise software for very large companies and our clients expect that we have already tested this new assembly. They would not accept us asking them to "test the new assembly and then make the appropriate .config file changes". The GAC policy makes more sense for MS because there is an unmanageable number of client apps but in our case we know who is using our assemblies and how. Assuming we really do want every client to get the new assembly, GAC seemed to the best way to get what we already had in COM.


    In short: From what you and MS's recommended GAC use is saying, GAC isn't meant to do what COM did. That means we lost functionality because someone decided we needed to be protected from ourselves "yes, I really do want to update all clients and I accept that responsibility. And trust me; our clients really do want my update/patch".


    Don't mean to sound angry, just hammering my point home :). All these people “misusing” the GAC are just trying to regain lost functionality.

    Maybe my statements aren’t accurate at all anyway, if not, I'd love to hear about it.


    Thanks
    Peter Thomas

  • Anonymous
    April 18, 2004
    The comment has been removed

  • Anonymous
    June 17, 2004
    I don't know if it is a good forum to raise my question?
    Actually what is happening is related to GAC only.

    In my application i am using both managed and unmanaged DLLs.

    However if while linking, i specify library order as "unmanaged.lib and managed.lib" then application works fine.
    But if i reverse the order i.e "managed.lib and unmanaged.lib" then application fails to load the assembly from GAC.

    Further with this if i remove Assembly from GAC and put it in the application path then also everything works fine.

    Now can anybody suggest me why is this happening and whether in such scenario whether i use or avoid using GAC.

  • Anonymous
    June 18, 2004
    The three big issues that I see in MSI deployment of assemblies into the GAC are these:
    1. Assemblies aren't committed to the GAC until the end of the install (a two-phase commit is described in the docs). Anything reasonable you want to do during the install (start a service, call a custom action) falls flat on its face because the assemblies aren't in the GAC yet. Every other use of installed files works fine, it's just this GAC case that doesn't work.
    2. Updating based on assembly version causes havoc. Replacement rules on disk use file version, replacement rules in the GAC use assembly version - that just ruins everyone's automated build and install processes that have relied on file version for ever to cause file replacement. The 1.1 framework lets you put a FileVersion in the MsiAssemblyName table, but that's little known and most build tools don't do it for you automatically.
    3. Policy files are difficult. You can put the first one in to redirect clients, but later on if you need to replace it, you're just back with the problem of how to replace an assembly in the GAC with a deployment project - it's the same assembly-update problem you thought you'd solved by using a policy file.

    So the number one reason I advise people not to use the GAC is because its integration with MSI is inconsistent with the way people expect installs to work, and the GAC causes a lot of issues in this area.

  • Anonymous
    June 18, 2004
    The comment has been removed

  • Anonymous
    June 19, 2004
    The comment has been removed

  • Anonymous
    June 20, 2004
    The comment has been removed

  • Anonymous
    July 01, 2004
    The comment has been removed

  • Anonymous
    July 02, 2004
    The comment has been removed

  • Anonymous
    May 21, 2007
    I know there are a few articles and posts out there concerning deploying .Net assemblies and how to service

  • Anonymous
    September 13, 2007
    espn college football schedules 2004 2005

  • Anonymous
    January 21, 2009
    PingBack from http://www.keyongtech.com/427665-net-versioning

  • Anonymous
    June 01, 2009
    PingBack from http://uniformstores.info/story.php?id=18827

  • Anonymous
    June 08, 2009
    PingBack from http://toenailfungusite.info/story.php?id=2969