code it

Martins Tech Blog

Global Assembly Cache reloaded

Das .NET Framework 4 ist nun schon ein paar Tage alt und abgesehen von tollen neuen Features bringt es auch einige gewöhnungsbedüftige Sachverhalte mit sich. Einer davon ist die Änderung im Global Assembly Cache.

Wer bisher die Fusion-Ansicht des Global Assembly Cache verwendet hat und per Drag & Drop Assemblies installiert hat, wird bemerken, dass alle neuen Assemblies sich nicht mehr installieren lassen, obwohl keine Fehlermeldung erscheint. Installiert man die Assemblies hingegen per gacutil, so wird man feststellen, dass zwar eine Erfolgsmeldung kommt, aber unter C:\Windows\assembly keine Veränderung geschieht.

Woran liegt das? Mit dem .NET Framework 4 gab es einige Änderungen im Konzept des GAC. Hier ein kurzer Auszug aus der MSDN:

In .NET Framework 4.0, the GAC went through a few changes. The concept of placing assemblies into a global directory began in CLR v1.1. In case of .NET Framework 1.1 (which had CLR v1.1) and .NET Framework 2.0 (which had CLR 2.0), the GAC was split into two, one for each CLR. This avoided the leaking of assemblies across CLR versions. 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.

Zusammengefasst bedeutet das, dass der GAC nicht mehr für alle Assemblies C:\Windows\assembly ist, sondern dass dort alle Pre-Framework-4-Assemblies liegen. Alle neuen Assemblies liegen im Assembly-Ordner des .NET-Frameworks (also z.B. C:\Windows\Microsoft.NET\assembly).

 

Für mich erklärt der MSDN-Auszug nun nicht ganz, warum hier ein anderer Ordner notwendig war, der sich auch noch anders verhält als der bisherige (s. Bild) - irgendwie hatte man sich ja schon an die Fusion-Ansicht gewöhnt. Für mich bleiben bei der aktuellen Implementierung viele Fragen offen:

  • Hätte man nicht unter C:\Windows\assembly noch eine Ordnerebene einführen können, die die Frameworkversion widerspiegelt?
  • Weshalb hat der neue GAC keine Fusion-Ansicht, in der so wichtige Informationen wie der Public-Key-Token und die Culture auf einen Blick sichtbar sind?
  • Weshalb kann die Fusion-Ansicht im alten GAC per Drag & Drop nicht selbstständig in die richtigen Ordner installieren?
  • ....

Glücklich bin ich mit der jetzigen Lösung nicht, aber ich werde mich - wie viele andere - damit auch arrangieren. Und vielleicht kommt ja noch ein Update oder ServicePack, das alles wieder schön macht. 

WSP-Deployment und Shared Assemblies im GAC

Solutions im SharePoint installiert man in der Regel durch WSPs. Das ist auch ganz bequem. Dabei gibt es auch die Möglichkeit, diese im Global Assembly Cache zu installieren - z.B. wenn man bestimmte Berechtigungen braucht.

Interessant wird es, wenn nun mehrere Projekte eine Assembly gemeinsam benutzen. Grundsätzlich ist das Vorgehen in diesem Fall recht einfach - man definiert eine Trace Reference. Hier sind ein paar Sätze aus Junfeng Zhangs Blog zum Thema:

When you install an assembly to GAC, you have the option to specify an Assembly Trace Reference.

And we strongly recommend that you specify a trace reference, for the reason I will discuss below.

The idea behind trace reference is really simple. When multiple applications install the same assembly, and one application is uninstalled (thus uninstall the assembly it carries), other applications won't be broken.

Leider bietet die Installationroutine im SharePoint diese Möglichkeit nicht. Die Gründe finden sich in den SharePoint-Administration-Assemblies: 

Man erkennt recht gut, dass im InstallAssembly als Referenz immer fest IntPtr.Zero übergeben wird.

Damit besteht hier diese Möglichkeit leider nicht und man kann auch mit Konfigurationen nicht Eingriff nehmen. Von mehreren Komponenten genutzte Assemblies können somit nicht in den GAC installiert werden, nicht gemeinsam genutzt werden oder es muss technisch oder manuell geprüft werden, ob nach der Deinstallation von Solutions diese Assemblies noch im GAC sind.

Bleibt zu hoffen, dass die SharePoint-Entwickler in künftigen Versionen diese Möglichkeit noch implementieren.

Assembly aus GAC wiederherstellen

Im Leben eines Microsoft-Entwicklers kommt es hin und wieder vor, dass man DLLs aus dem GAC wiederherstellen muss. Das Standardverhalten in der Windows-GUI lässt aber nur ein komplettes Deinstallieren (=Entfernen) aus dem Global Assembly Cache zu und damit wäre die DLL für immer verloren.

Hier kommt nun die gute alte Eingabeaufforderung zum Zuge. Wenn man damit in den GAC navigiert, bekommt man eine andere Ansicht als in der Windows-Oberfläche. Das erklärt auch, weshalb der Explorer mit einem Hinzufügen mittels Strg+C und Strg+V etwas überfordert ist und das Ganze schlichtweg ignoriert.

Von hier aus kann man sich nun weiter in die Tiefen des GAC begeben. Normale MSIL-Assemblies findet man in GAC_MSIL. Hier ist für jede Assembly ein Ordner angelegt, der wiederum einen oder mehrere Ordner mit Versionskennzeichnungen. Hier findet man dann die installierte DLL und kann diese z.B. mit dem Copy-Befehl an eine andere Stelle kopieren.

Einen interessanten Nebeneffekt kann man nun erzielen, wenn man in der Eingabeaufforderung einen solchen Ordner geöffnet hat und dann über die Windows-Oberfläche die DLL aus dem GAC deinstalliert und wieder hinzufügen möchte. Dann schlägt das Hinzufügen mit der Meldung "Das Erstellen von <DLL> oder das Erstellen einer Schattenkopie ist nicht möglich, wenn diese Datei bereits vorhanden ist."

 

In diesem Fall kann man das Problem mit dem Schließen der Eingabeaufforderung beheben.