302

%windir%\Microsoft.NET\assembly\ is the new GAC. Does it mean now we have to manage two GACs, one for .NET 2.0-3.5 applications and the other for .NET 4.0 applications?

The question is, why?

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
Max Toro
  • 27,264
  • 10
  • 71
  • 109

3 Answers3

182

Yes since there are 2 distinct Global Assembly Cache (GAC), you will have to manage each of them individually.

In .NET Framework 4.0, the GAC went through a few changes. The GAC was split into two, one for each CLR.

The CLR version used for both .NET Framework 2.0 and .NET Framework 3.5 is CLR 2.0. There was no need in the previous two framework releases to split GAC. The problem of breaking older applications in Net Framework 4.0.

To avoid issues between CLR 2.0 and CLR 4.0 , the GAC is now split into private GAC’s for each runtime.The main change is that CLR v2.0 applications now cannot see CLR v4.0 assemblies in the GAC.

Source

Why?

It seems to be because there was a CLR change in .NET 4.0 but not in 2.0 to 3.5. The same thing happened with 1.1 to 2.0 CLR. It seems that the GAC has the ability to store different versions of assemblies as long as they are from the same CLR. They do not want to break old applications.

See the following information in MSDN about the GAC changes in 4.0.

For example, if both .NET 1.1 and .NET 2.0 shared the same GAC, then a .NET 1.1 application, loading an assembly from this shared GAC, could get .NET 2.0 assemblies, thereby breaking the .NET 1.1 application

The CLR version used for both .NET Framework 2.0 and .NET Framework 3.5 is CLR 2.0. As a result of this, there was no need in the previous two framework releases to split the GAC. The problem of breaking older (in this case, .NET 2.0) applications resurfaces in Net Framework 4.0 at which point CLR 4.0 released. Hence, to avoid interference issues between CLR 2.0 and CLR 4.0, the GAC is now split into private GACs for each runtime.

As the CLR is updated in future versions you can expect the same thing. If only the language changes then you can use the same GAC.

Community
  • 1
  • 1
Brian R. Bondy
  • 314,085
  • 114
  • 576
  • 619
  • 18
    That blog post merely restates the OP's discovery, it doesn't explain *why* the GAC needed to be split. It isn't obvious, the original GAC would have been quite capable of keeping the 4.0 assemblies separate. They have a new [AssemblyVersion] – Hans Passant Apr 17 '10 at 23:36
  • 1
    @Hans: Maybe not the exact reason but it does say: "To avoid issues between CLR 2.0 and CLR 4.0", also the question had 2 questions inside of it. The second question being: "does it mean now we have to manage two GACs, one for .NET 2.0-3.5 apps and the other for .NET 4.0 apps?" – Brian R. Bondy Apr 17 '10 at 23:44
67

I also wanted to know why 2 GAC and found the following explanation by Mark Miller in the comments section of .NET 4.0 has 2 Global Assembly Cache (GAC):

Mark Miller said... June 28, 2010 12:13 PM

Thanks for the post. "Interference issues" was intentionally vague. At the time of writing, the issues were still being investigated, but it was clear there were several broken scenarios.

For instance, some applications use Assemby.LoadWithPartialName to load the highest version of an assembly. If the highest version was compiled with v4, then a v2 (3.0 or 3.5) app could not load it, and the app would crash, even if there were a version that would have worked. Originally, we partitioned the GAC under it's original location, but that caused some problems with windows upgrade scenarios. Both of these involved code that had already shipped, so we moved our (version-partitioned GAC to another place.

This shouldn't have any impact to most applications, and doesn't add any maintenance burden. Both locations should only be accessed or modified using the native GAC APIs, which deal with the partitioning as expected. The places where this does surface are through APIs that expose the paths of the GAC such as GetCachePath, or examining the path of mscorlib loaded into managed code.

It's worth noting that we modified GAC locations when we released v2 as well when we introduced architecture as part of the assembly identity. Those added GAC_MSIL, GAC_32, and GAC_64, although all still under %windir%\assembly. Unfortunately, that wasn't an option for this release.

Hope it helps future readers.

Atif Aziz
  • 34,202
  • 16
  • 59
  • 71
Jasl
  • 1,345
  • 1
  • 11
  • 14
66

It doesn't make a lot of sense, the original GAC was already quite capable of storing different versions of assemblies. And there's little reason to assume a program will ever accidentally reference the wrong assembly, all the .NET 4 assemblies got the [AssemblyVersion] bumped up to 4.0.0.0. The new in-process side-by-side feature should not change this.

My guess: there were already too many .NET projects out there that broke the "never reference anything in the GAC directly" rule. I've seen it done on this site several times.

Only one way to avoid breaking those projects: move the GAC. Back-compat is sacred at Microsoft.

Hans Passant
  • 873,011
  • 131
  • 1,552
  • 2,371
  • 3
    This is the only answer that tries to explain *why* this is the case. +1 – Ed S. Apr 17 '10 at 23:59
  • 1
    @Hans Passant: What do you mean by "never reference anything in the GAC directly" rule ? – Max Toro Apr 18 '10 at 00:04
  • 2
    @Max: there are two copies of the .NET assemblies on your machine. Those meant to be reference assemblies in c:\windows\microsoft.net and c:\program files\reference assemblies. And the ones used at runtime, the GAC @ c:\windows\assembly. They are not the same, 64-bit would be an example. Microsoft did their best to avoid anybody referencing the GAC ones with a shell extension handler. And the Add Reference dialog. Not 100% effective – Hans Passant Apr 18 '10 at 00:22
  • @Hans Passant: A direct reference is something like 'c:\WINDOWS\assembly\GAC_MSIL\System\2.0.0.0__b77a5c561934e089\System.dll', I don't see how adding a new version would break that reference. – Max Toro Apr 18 '10 at 00:23
  • @Hans: It has the ability to store different versions of the assembly within the same CLR version... so it does make sense. – Brian R. Bondy Apr 18 '10 at 00:37
  • It breaks when CLR4 is actually used, it will happily load the incompatible v2 assembly. – Hans Passant Apr 18 '10 at 00:41
  • 2
    @Hans Passant: "And there's little reason to assume a program will ever accidentally reference the wrong assembly" I think the key here is `Assembly.LoadWithPartialName`, what happens if we have 2 versions of the assembly on the GAC ? – Max Toro Apr 18 '10 at 00:58
  • @Max: .NET assemblies are never referenced with a partial name, they are strong-named. – Hans Passant Apr 18 '10 at 01:21
  • @Hans Passant: Like you say, referencing the wrong assembly is not the issue, loading the wrong assembly is. "For example, if both .NET 1.1 and .NET 2.0 shared the same GAC, then a .NET 1.1 application, loading an assembly from this shared GAC, could get .NET 2.0 assemblies, thereby breaking the .NET 1.1 application." http://msdn.microsoft.com/en-us/magazine/dd727509.aspx – Max Toro Apr 18 '10 at 02:22
  • @Max: It's the exact same argument, without an explanation of how that could happen. "Leaking" doesn't mean anything to me. This starts to smell like "better be safe then sorry". – Hans Passant Apr 18 '10 at 02:44