.NET 4.0 ha un nuovo GAC, perché?


300

%windir%\Microsoft.NET\assembly\è il nuovo GAC . Significa ora che dobbiamo gestire due GAC, uno per le applicazioni .NET 2.0-3.5 e l'altro per le applicazioni .NET 4.0?

La domanda è: perché?


7
grazie per aver posto la domanda .. Sono anche molto confuso quando non ho trovato gac nella sua posizione originale :)
Jasl

2
Bella domanda ... Mille grazie.
smwikipedia,

1
+1 per la tua domanda. Ho iniziato lo sviluppo con NET 4.0 ed ero confuso dal "doppio" problema GAC.
Hernán,

3
Sono servite alcune iterazioni, ma Microsoft ha finalmente portato DLL Hell su .NET. Sìì!
nothingisnecessary

Risposte:


181

Sì, poiché esistono 2 Global Assembly Cache (GAC) distinti, dovrai gestirli singolarmente.

In .NET Framework 4.0, il GAC ha subito alcune modifiche. Il GAC è stato diviso in due, uno per ciascun CLR.

La versione CLR utilizzata per .NET Framework 2.0 e .NET Framework 3.5 è CLR 2.0. Nelle due versioni precedenti del framework non era necessario dividere GAC. Il problema di rompere le applicazioni meno recenti in Net Framework 4.0.

Per evitare problemi tra CLR 2.0 e CLR 4.0, il GAC è ora suddiviso in GAC privati ​​per ogni runtime. La principale modifica è che le applicazioni CLR v2.0 ora non possono vedere gli assembly CLR v4.0 nel GAC.

fonte

Perché?

Sembra che ci sia stata una modifica CLR in .NET 4.0 ma non in 2.0 a 3.5. La stessa cosa è successa con CLR da 1.1 a 2.0. Sembra che il GAC abbia la capacità di memorizzare versioni diverse di assiemi purché provengano dallo stesso CLR. Non vogliono rompere le vecchie applicazioni.

Vedere le seguenti informazioni in MSDN sulle modifiche GAC in 4.0 .

Ad esempio, se sia .NET 1.1 che .NET 2.0 condividevano lo stesso GAC, un'applicazione .NET 1.1, caricando un assembly da questo GAC condiviso, poteva ottenere assembly .NET 2.0, interrompendo così l'applicazione .NET 1.1

La versione CLR utilizzata per .NET Framework 2.0 e .NET Framework 3.5 è CLR 2.0. Di conseguenza, nelle due versioni precedenti del framework non era necessario dividere il GAC. Il problema di rompere le applicazioni meno recenti (in questo caso .NET 2.0) riappare in Net Framework 4.0, a quel punto è stato rilasciato CLR 4.0. Pertanto, per evitare problemi di interferenza tra CLR 2.0 e CLR 4.0, il GAC è ora suddiviso in GAC privati ​​per ogni runtime.

Poiché il CLR verrà aggiornato nelle versioni future, puoi aspettarti la stessa cosa. Se cambia solo la lingua, puoi utilizzare lo stesso GAC.


18
Quel post sul blog riafferma semplicemente la scoperta del PO, non spiega perché il GAC dovesse essere diviso. Non è ovvio, il GAC originale sarebbe stato abbastanza in grado di mantenere separati gli assiemi 4.0. Hanno una nuova [AssemblyVersion]
Hans Passant,

1
@Hans: Forse non è il motivo esatto ma dice: "Per evitare problemi tra CLR 2.0 e CLR 4.0", anche la domanda conteneva 2 domande al suo interno. La seconda domanda è: "significa ora che dobbiamo gestire due GAC, uno per le app .NET 2.0-3.5 e l'altro per le app .NET 4.0?"
Brian R. Bondy,

2
Dovresti citare questo, da uno dei tuoi link: "Ad esempio, se sia .NET 1.1 che .NET 2.0 condividevano lo stesso GAC, un'applicazione .NET 1.1, caricando un assembly da questo GAC condiviso, potrebbe ottenere assembly .NET 2.0 , interrompendo così l'applicazione .NET 1.1. "
Max Toro,

67

Volevo anche sapere perché 2 GAC e ho trovato la seguente spiegazione di Mark Miller nella sezione commenti di .NET 4.0 ha 2 Global Assembly Cache (GAC) :

Mark Miller ha detto ... 28 giugno 2010 12:13 PM

Grazie per il post. "Problemi di interferenza" era intenzionalmente vago. Al momento della stesura del presente documento, i problemi erano ancora oggetto di indagine, ma era chiaro che c'erano diversi scenari rotti.

Ad esempio, alcune applicazioni utilizzano Assemby.LoadWithPartialName per caricare la versione più alta di un assembly. Se la versione più alta è stata compilata con v4, quindi un'app v2 (3.0 o 3.5) non è in grado di caricarla e l'app si arresterebbe in modo anomalo, anche se esistesse una versione che avrebbe funzionato. Inizialmente, abbiamo partizionato il GAC nella sua posizione originale, ma ciò ha causato alcuni problemi con gli scenari di aggiornamento di Windows. Entrambi riguardavano il codice che era già stato spedito, quindi abbiamo spostato il nostro (GAC partizionato in versione in un altro posto.

Ciò non dovrebbe avere alcun impatto sulla maggior parte delle applicazioni e non aggiunge alcun onere di manutenzione. È possibile accedere o modificare entrambe le posizioni solo tramite le API GAC native, che gestiscono il partizionamento come previsto. I luoghi in cui ciò emerge sono tramite API che espongono i percorsi del GAC come GetCachePath o esaminano il percorso di mscorlib caricato nel codice gestito.

Vale la pena notare che abbiamo modificato le posizioni GAC anche quando abbiamo rilasciato v2 quando abbiamo introdotto l'architettura come parte dell'identità dell'assembly. Quelli hanno aggiunto GAC_MSIL, GAC_32 e GAC_64, sebbene tutti ancora sotto% windir% \ assembly. Sfortunatamente, questa non era un'opzione per questa versione.

Spero che aiuti i futuri lettori.


3
I commenti di Miller sull'articolo collegato forniscono una visione privilegiata dell'argomento.
Nimesh Madhavan,

66

Non ha molto senso, il GAC originale era già abbastanza in grado di memorizzare diverse versioni di assiemi. E ci sono pochi motivi per presumere che un programma possa mai fare riferimento accidentalmente all'assembly sbagliato, tutti gli assembly .NET 4 hanno ottenuto che [AssemblyVersion] sia stato bloccato fino alla 4.0.0.0. La nuova funzionalità side-by-side in-process non dovrebbe cambiarla.

La mia ipotesi: c'erano già troppi progetti .NET là fuori che hanno infranto la regola "mai fare riferimento direttamente a GAC". L'ho visto fare su questo sito diverse volte.

Un solo modo per evitare di interrompere quei progetti: spostare il GAC. Back-compat è sacro in Microsoft.


3
Questa è l'unica risposta che cerca di spiegare perché questo è il caso. +1
Ed S.

1
@Hans Passant: cosa intendi con la regola "non fare mai riferimento a nulla direttamente nella GAC"?
Max Toro,

2
@Max: ci sono due copie degli assembly .NET sul tuo computer. Quelli intesi come assiemi di riferimento in c: \ windows \ microsoft.net e c: \ programmi file \ assiemi di riferimento. E quelli usati in fase di esecuzione, GAC @ c: \ windows \ assembly. Non sono gli stessi, 64 bit sarebbe un esempio. Microsoft ha fatto del suo meglio per evitare che qualcuno facesse riferimento a quelli GAC con un gestore di estensione shell. E la finestra di dialogo Aggiungi riferimento. Non efficace al 100%
Hans Passant,

@Hans Passant: un riferimento diretto è qualcosa come "c: \ WINDOWS \ assembly \ GAC_MSIL \ System \ 2.0.0.0__b77a5c561934e089 \ System.dll", non vedo come l'aggiunta di una nuova versione interrompa tale riferimento.
Max Toro,

2
@Hans Passant: "E ci sono poche ragioni per presumere che un programma farà mai riferimento accidentalmente all'assembly sbagliato" Penso che la chiave qui sia Assembly.LoadWithPartialName, cosa succede se abbiamo 2 versioni dell'assembly sul GAC?
Max Toro,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.