.NET 4.0 hat ein neues GAC, warum?


300

%windir%\Microsoft.NET\assembly\ist das neue GAC . Bedeutet dies, dass wir jetzt zwei GACs verwalten müssen, einen für .NET 2.0-3.5-Anwendungen und einen für .NET 4.0-Anwendungen?

Die Frage ist, warum?


7
danke, dass du die Frage gestellt hast. Ich bin auch sehr verwirrt, als ich gac nicht an seinem ursprünglichen Ort gefunden habe :)
Jasl

2
Gute Frage ... Vielen Dank.
Smwikipedia

1
+1 für deine Frage. Ich begann mit der Entwicklung unter NET 4.0 und war durch das "duale" GAC-Problem verwirrt.
Hernán

3
Es dauerte ein paar Iterationen, aber Microsoft brachte schließlich DLL Hell zu .NET. Yay!
nothingisnecessary

Antworten:


181

Ja, da es zwei verschiedene Global Assembly Cache (GAC) gibt, müssen Sie jeden einzeln verwalten.

In .NET Framework 4.0 hat der GAC einige Änderungen vorgenommen. Das GAC wurde in zwei Teile aufgeteilt, einen für jede CLR.

Die für .NET Framework 2.0 und .NET Framework 3.5 verwendete CLR-Version ist CLR 2.0. In den beiden vorherigen Framework-Versionen war es nicht erforderlich, GAC aufzuteilen. Das Problem, ältere Anwendungen in Net Framework 4.0 zu beschädigen.

Um Probleme zwischen CLR 2.0 und CLR 4.0 zu vermeiden, wird der GAC jetzt für jede Laufzeit in private GACs aufgeteilt. Die Hauptänderung besteht darin, dass CLR v2.0-Anwendungen jetzt keine CLR v4.0-Assemblys im GAC sehen können.

Quelle

Warum?

Dies scheint darauf zurückzuführen zu sein, dass in .NET 4.0 eine CLR-Änderung vorgenommen wurde, nicht jedoch in 2.0 auf 3.5. Das gleiche passierte mit 1.1 bis 2.0 CLR. Es scheint, dass der GAC die Möglichkeit hat, verschiedene Versionen von Baugruppen zu speichern, solange diese aus derselben CLR stammen. Sie wollen keine alten Anwendungen brechen.

In den folgenden Informationen in MSDN finden Sie Informationen zu den GAC-Änderungen in 4.0 .

Wenn beispielsweise sowohl .NET 1.1 als auch .NET 2.0 denselben GAC gemeinsam nutzen, kann eine .NET 1.1-Anwendung, die eine Assembly von diesem gemeinsam genutzten GAC lädt, .NET 2.0-Assemblys erhalten, wodurch die .NET 1.1-Anwendung beschädigt wird

Die CLR-Version, die sowohl für .NET Framework 2.0 als auch für .NET Framework 3.5 verwendet wird, ist CLR 2.0. Infolgedessen war es in den beiden vorherigen Framework-Releases nicht erforderlich, den GAC aufzuteilen. Das Problem, ältere (in diesem Fall .NET 2.0) Anwendungen zu beschädigen, tritt in Net Framework 4.0 erneut auf. Zu diesem Zeitpunkt wurde CLR 4.0 veröffentlicht. Um Interferenzprobleme zwischen CLR 2.0 und CLR 4.0 zu vermeiden, wird der GAC jetzt für jede Laufzeit in private GACs aufgeteilt.

Da die CLR in zukünftigen Versionen aktualisiert wird, können Sie dasselbe erwarten. Wenn sich nur die Sprache ändert, können Sie denselben GAC verwenden.


18
Dieser Blog-Beitrag wiederholt lediglich die Entdeckung des OP und erklärt nicht, warum der GAC aufgeteilt werden musste. Es ist nicht offensichtlich, dass der ursprüngliche GAC durchaus in der Lage gewesen wäre, die 4.0-Baugruppen getrennt zu halten. Sie haben eine neue [AssemblyVersion]
Hans Passant

1
@Hans: Vielleicht nicht der genaue Grund, aber es heißt: "Um Probleme zwischen CLR 2.0 und CLR 4.0 zu vermeiden", enthielt die Frage auch zwei Fragen. Die zweite Frage lautet: "Bedeutet dies, dass wir jetzt zwei GACs verwalten müssen, einen für .NET 2.0-3.5-Apps und einen für .NET 4.0-Apps?"
Brian R. Bondy

2
Sie sollten dies über einen Ihrer Links zitieren: "Wenn beispielsweise .NET 1.1 und .NET 2.0 denselben GAC gemeinsam nutzen, kann eine .NET 1.1-Anwendung, die eine Assembly aus diesem gemeinsam genutzten GAC lädt, .NET 2.0-Assemblys erhalten Dadurch wird die .NET 1.1-Anwendung beschädigt. "
Max Toro

67

Ich wollte auch wissen, warum 2 GAC und fand die folgende Erklärung von Mark Miller im Kommentarbereich von .NET 4.0 mit 2 Global Assembly Cache (GAC) :

Mark Miller sagte ... 28. Juni 2010 12:13 Uhr

Danke für den Beitrag. "Interferenzprobleme" waren absichtlich vage. Zum Zeitpunkt des Schreibens wurden die Probleme noch untersucht, aber es war klar, dass es mehrere kaputte Szenarien gab.

Einige Anwendungen verwenden beispielsweise Assemby.LoadWithPartialName, um die höchste Version einer Assembly zu laden. Wenn die höchste Version mit v4 kompiliert wurde, konnte sie von einer v2-App (3.0 oder 3.5) nicht geladen werden, und die App stürzte ab, selbst wenn es eine Version gegeben hätte, die funktioniert hätte. Ursprünglich haben wir den GAC unter seinem ursprünglichen Speicherort partitioniert, aber dies verursachte einige Probleme mit Windows-Upgrade-Szenarien. Bei beiden handelte es sich um Code, der bereits ausgeliefert wurde. Daher haben wir unseren (version-partitionierten GAC) an einen anderen Ort verschoben.

Dies sollte für die meisten Anwendungen keine Auswirkungen haben und verursacht keinen zusätzlichen Wartungsaufwand. Auf beide Speicherorte sollte nur mit den nativen GAC-APIs zugegriffen oder diese geändert werden, die die Partitionierung wie erwartet behandeln. Die Stellen, an denen dies auftritt, sind APIs, die die Pfade des GAC verfügbar machen, z. B. GetCachePath, oder die Untersuchung des in verwalteten Code geladenen Pfads von mscorlib.

Es ist erwähnenswert, dass wir die GAC-Speicherorte geändert haben, als wir v2 veröffentlicht haben, als wir die Architektur als Teil der Assembly-Identität eingeführt haben. Diese fügten GAC_MSIL, GAC_32 und GAC_64 hinzu, obwohl alle noch unter% windir% \ Assembly stehen. Leider war dies für diese Version keine Option.

Hoffe es hilft zukünftigen Lesern.


3
Millers Kommentare zu dem verlinkten Artikel bieten eine Insider-Sicht auf das Thema.
Nimesh Madhavan

66

Es macht nicht viel Sinn, das ursprüngliche GAC war bereits in der Lage, verschiedene Versionen von Baugruppen zu speichern. Und es gibt wenig Grund anzunehmen, dass ein Programm jemals versehentlich auf die falsche Assembly verweist. Bei allen .NET 4-Assemblys wurde die [AssemblyVersion] auf 4.0.0.0 erhöht. Die neue In-Process-Side-by-Side-Funktion sollte dies nicht ändern.

Meine Vermutung: Es gab bereits zu viele .NET-Projekte, die gegen die Regel "Nie direkt auf etwas im GAC verweisen" verstoßen haben. Ich habe es mehrmals auf dieser Seite gesehen.

Nur eine Möglichkeit, diese Projekte nicht zu beschädigen: Verschieben Sie den GAC. Back-Compat ist bei Microsoft heilig.


3
Dies ist die einzige Antwort, die zu erklären versucht, warum dies der Fall ist. +1
Ed S.

1
@ Hans Passant: Was meinst du mit der Regel "Niemals direkt auf etwas im GAC verweisen"?
Max Toro

2
@Max: Auf Ihrem Computer befinden sich zwei Kopien der .NET-Assemblys. Dies sind Referenzassemblys in c: \ windows \ microsoft.net und c: \ program files \ reference Assemblys. Und diejenigen, die zur Laufzeit verwendet werden, die GAC @ c: \ windows \ Assembly. Sie sind nicht gleich, 64-Bit wäre ein Beispiel. Microsoft hat sein Bestes getan, um zu vermeiden, dass jemand mit einem Shell-Erweiterungshandler auf die GAC verweist. Und das Dialogfeld "Referenz hinzufügen". Nicht 100% wirksam
Hans Passant

@Hans Passant: Eine direkte Referenz ist so etwas wie 'c: \ WINDOWS \ Assembly \ GAC_MSIL \ System \ 2.0.0.0__b77a5c561934e089 \ System.dll'. Ich sehe nicht, wie das Hinzufügen einer neuen Version diese Referenz beschädigen würde.
Max Toro

2
@Hans Passant: "Und es gibt wenig Grund anzunehmen, dass ein Programm jemals versehentlich auf die falsche Assembly verweist." Ich denke, der Schlüssel hier ist Assembly.LoadWithPartialName, was passiert, wenn wir zwei Versionen der Assembly auf dem GAC haben?
Max Toro
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.