.NET 4.0 a un nouveau GAC, pourquoi?


300

%windir%\Microsoft.NET\assembly\est le nouveau GAC . Cela signifie-t-il maintenant que nous devons gérer deux GAC, l'un pour les applications .NET 2.0-3.5 et l'autre pour les applications .NET 4.0?

La question est, pourquoi?


7
merci d'avoir posé la question .. je suis aussi très confus quand je n'ai pas trouvé de gac dans son emplacement d'origine :)
Jasl

2
Bonne question ... Merci beaucoup.
smwikipedia

1
+1 pour votre question. J'ai commencé le développement sous NET 4.0 et j'ai été troublé par le problème "double" de GAC.
Hernán

3
Il leur a fallu quelques itérations, mais Microsoft a finalement apporté DLL Hell à .NET. Yay!
rien n'est nécessaire le

Réponses:


181

Oui, car il existe 2 Global Assembly Cache (GAC) distincts, vous devrez gérer chacun d'eux individuellement.

Dans .NET Framework 4.0, le GAC a subi quelques modifications. Le GAC a été divisé en deux, un pour chaque CLR.

La version CLR utilisée pour .NET Framework 2.0 et .NET Framework 3.5 est CLR 2.0. Il n'était pas nécessaire dans les deux versions précédentes du framework de diviser GAC. Le problème de la rupture des anciennes applications dans Net Framework 4.0.

Pour éviter les problèmes entre CLR 2.0 et CLR 4.0, le GAC est désormais divisé en GAC privés pour chaque exécution. La principale modification est que les applications CLR v2.0 ne peuvent plus voir les assemblys CLR v4.0 dans le GAC.

La source

Pourquoi?

Cela semble être dû au fait qu'il y a eu un changement CLR dans .NET 4.0 mais pas dans 2.0 à 3.5. La même chose s'est produite avec 1.1 à 2.0 CLR. Il semble que le GAC ait la capacité de stocker différentes versions d'assemblages tant qu'ils proviennent du même CLR. Ils ne veulent pas casser les anciennes applications.

Consultez les informations suivantes dans MSDN sur les modifications GAC dans 4.0 .

Par exemple, si .NET 1.1 et .NET 2.0 partageaient le même GAC, une application .NET 1.1, chargeant un assembly à partir de ce GAC partagé, pourrait obtenir des assemblys .NET 2.0, cassant ainsi l'application .NET 1.1

La version CLR utilisée pour .NET Framework 2.0 et .NET Framework 3.5 est CLR 2.0. En conséquence, il n'était pas nécessaire dans les deux versions précédentes du framework de diviser le GAC. Le problème de la rupture des anciennes applications (dans ce cas, .NET 2.0) refait surface dans Net Framework 4.0, date à laquelle CLR 4.0 est sorti. Par conséquent, pour éviter les problèmes d'interférence entre CLR 2.0 et CLR 4.0, le GAC est désormais divisé en GAC privés pour chaque exécution.

Comme le CLR est mis à jour dans les futures versions, vous pouvez vous attendre à la même chose. Si seule la langue change, vous pouvez utiliser le même GAC.


18
Ce billet de blog réaffirme simplement la découverte du PO, il n'explique pas pourquoi le GAC devait être divisé. Ce n'est pas évident, le GAC d'origine aurait été tout à fait capable de garder les assemblys 4.0 séparés. Ils ont une nouvelle [AssemblyVersion]
Hans Passant

1
@Hans: Peut-être pas la raison exacte, mais il dit: "Pour éviter les problèmes entre CLR 2.0 et CLR 4.0", la question comportait également 2 questions. La deuxième question étant: "cela signifie-t-il maintenant que nous devons gérer deux GAC, l'un pour les applications .NET 2.0-3.5 et l'autre pour les applications .NET 4.0?"
Brian R. Bondy

2
Vous devez citer ceci à partir de l'un de vos liens: "Par exemple, si .NET 1.1 et .NET 2.0 partagent le même GAC, une application .NET 1.1, chargeant un assembly à partir de ce GAC partagé, pourrait obtenir des assemblys .NET 2.0 , cassant ainsi l'application .NET 1.1. "
Max Toro

67

Je voulais également savoir pourquoi 2 GAC et j'ai trouvé l' explication suivante de Mark Miller dans la section commentaires de .NET 4.0 a 2 Global Assembly Cache (GAC) :

Mark Miller a dit ... 28 juin 2010 12:13 PM

Merci pour le post. Les «problèmes d'interférence» étaient intentionnellement vagues. Au moment de la rédaction du présent rapport, les problèmes étaient toujours à l'étude, mais il était clair qu'il y avait plusieurs scénarios brisés.

Par exemple, certaines applications utilisent Assemby.LoadWithPartialName pour charger la version la plus élevée d'un assembly. Si la version la plus élevée était compilée avec la v4, une application v2 (3.0 ou 3.5) ne pouvait pas la charger et l'application se bloquait, même s'il existait une version qui aurait fonctionné. À l'origine, nous avons partitionné le GAC sous son emplacement d'origine, mais cela a causé des problèmes avec les scénarios de mise à niveau de Windows. Ces deux impliquaient du code qui avait déjà été livré, nous avons donc déplacé notre (GAC partitionné en version vers un autre endroit.

Cela ne devrait pas avoir d'impact sur la plupart des applications et n'ajoute aucune charge de maintenance. Les deux emplacements doivent uniquement être accessibles ou modifiés à l'aide des API GAC natives, qui traitent le partitionnement comme prévu. Les endroits où cela fait surface sont via des API qui exposent les chemins du GAC tels que GetCachePath, ou examinent le chemin de mscorlib chargé dans le code managé.

Il convient de noter que nous avons modifié les emplacements GAC lorsque nous avons publié la v2 ainsi que lorsque nous avons introduit l'architecture dans le cadre de l'identité de l'assembly. Ceux-ci ont ajouté GAC_MSIL, GAC_32 et GAC_64, bien que tous soient toujours sous% windir% \ assembly. Malheureusement, ce n'était pas une option pour cette version.

J'espère que cela aidera les futurs lecteurs.


3
Les commentaires de Miller sur l'article lié fournissent une vue d'initiés sur le sujet.
Nimesh Madhavan

66

Cela n'a pas beaucoup de sens, le GAC d'origine était déjà tout à fait capable de stocker différentes versions d'assemblages. Et il y a peu de raisons de supposer qu'un programme référencera jamais accidentellement le mauvais assemblage, tous les assemblys .NET 4 ont obtenu le [AssemblyVersion] remonté à 4.0.0.0. La nouvelle fonction côte à côte en cours ne devrait pas changer cela.

Ma conjecture: il y avait déjà trop de projets .NET qui ont enfreint la règle "ne jamais rien référencer directement dans le GAC". Je l'ai vu plusieurs fois sur ce site.

Une seule façon d'éviter de casser ces projets: déplacer le GAC. La rétrocompatibilité est sacrée chez Microsoft.


3
C'est la seule réponse qui tente d'expliquer pourquoi c'est le cas. +1
Ed S.

1
@Hans Passant: Qu'entendez-vous par la règle "ne jamais rien référencer directement dans le GAC"?
Max Toro

2
@Max: il existe deux copies des assemblys .NET sur votre machine. Celles-ci sont censées être des assemblys de référence dans c: \ windows \ microsoft.net et c: \ program files \ reference assemblies. Et ceux utilisés lors de l'exécution, le GAC @ c: \ windows \ assembly. Ce ne sont pas les mêmes, 64 bits en seraient un exemple. Microsoft a fait de son mieux pour éviter que quiconque fasse référence à ceux du GAC avec un gestionnaire d'extension de shell. Et la boîte de dialogue Ajouter une référence. Pas 100% efficace
Hans Passant

@Hans Passant: Une référence directe est quelque chose comme 'c: \ WINDOWS \ assembly \ GAC_MSIL \ System \ 2.0.0.0__b77a5c561934e089 \ System.dll', je ne vois pas comment l'ajout d'une nouvelle version romprait cette référence.
Max Toro

2
@Hans Passant: "Et il y a peu de raisons de supposer qu'un programme référencera jamais accidentellement le mauvais assemblage" Je pense que la clé ici est Assembly.LoadWithPartialName, que se passe-t-il si nous avons 2 versions de l'assemblage sur le GAC?
Max Toro
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.