.NET 4.0 tiene un nuevo GAC, ¿por qué?

300

%windir%\Microsoft.NET\assembly\es el nuevo GAC . ¿Significa que ahora tenemos que administrar dos GAC, uno para aplicaciones .NET 2.0-3.5 y el otro para aplicaciones .NET 4.0?

La pregunta es, ¿por qué?

Max Toro
fuente
77
gracias por hacer la pregunta ... también estoy muy confundido cuando no encontré gac en su ubicación original :)
Jasl
2
Buena pregunta ... muchas gracias.
smwikipedia
1
+1 para tu pregunta. Comencé el desarrollo bajo NET 4.0 y estaba confundido por el problema "dual" de GAC.
Hernán
3
Les tomó algunas iteraciones, pero Microsoft finalmente trajo DLL Hell a .NET. ¡Hurra!
nada es necesario

Respuestas:

181

Sí, dado que hay 2 Caché de Asamblea Global (GAC) distintos, tendrá que administrar cada uno de ellos individualmente.

En .NET Framework 4.0, el GAC experimentó algunos cambios. El GAC se dividió en dos, uno para cada CLR.

La versión CLR utilizada para .NET Framework 2.0 y .NET Framework 3.5 es CLR 2.0. No hubo necesidad en los dos lanzamientos de framework anteriores para dividir GAC. El problema de romper aplicaciones antiguas en Net Framework 4.0.

Para evitar problemas entre CLR 2.0 y CLR 4.0, el GAC ahora se divide en GAC privados para cada tiempo de ejecución. El cambio principal es que las aplicaciones CLR v2.0 ahora no pueden ver los ensamblados CLR v4.0 en el GAC.

Fuente

¿Por qué?

Parece ser porque hubo un cambio de CLR en .NET 4.0 pero no en 2.0 a 3.5. Lo mismo sucedió con 1.1 a 2.0 CLR. Parece que el GAC tiene la capacidad de almacenar diferentes versiones de ensamblajes siempre que sean del mismo CLR. No quieren romper las viejas aplicaciones.

Consulte la siguiente información en MSDN sobre los cambios de GAC en 4.0 .

Por ejemplo, si .NET 1.1 y .NET 2.0 comparten el mismo GAC, entonces una aplicación .NET 1.1, que carga un ensamblado desde este GAC compartido, podría obtener ensamblados .NET 2.0, rompiendo así la aplicación .NET 1.1

La versión CLR utilizada para .NET Framework 2.0 y .NET Framework 3.5 es CLR 2.0. Como resultado de esto, no hubo necesidad en las dos versiones anteriores del marco para dividir el GAC. El problema de romper las aplicaciones más antiguas (en este caso, .NET 2.0) reaparece en Net Framework 4.0, momento en el que se lanzó CLR 4.0. Por lo tanto, para evitar problemas de interferencia entre CLR 2.0 y CLR 4.0, el GAC ahora se divide en GAC privados para cada tiempo de ejecución.

A medida que el CLR se actualiza en futuras versiones, puede esperar lo mismo. Si solo cambia el idioma, puede usar el mismo GAC.

Brian R. Bondy
fuente
18
Esa publicación de blog simplemente reafirma el descubrimiento del OP, no explica por qué el GAC necesitaba ser dividido. No es obvio, el GAC original habría sido bastante capaz de mantener separados los ensamblajes 4.0. Tienen una nueva [AsambleaVersión]
Hans Passant
1
@Hans: Tal vez no sea la razón exacta pero dice: "Para evitar problemas entre CLR 2.0 y CLR 4.0", también la pregunta tenía 2 preguntas dentro. La segunda pregunta es: "¿significa que ahora tenemos que administrar dos GAC, uno para aplicaciones .NET 2.0-3.5 y el otro para aplicaciones .NET 4.0?"
Brian R. Bondy
2
Debe citar esto, en uno de sus enlaces: "Por ejemplo, si .NET 1.1 y .NET 2.0 comparten el mismo GAC, entonces una aplicación .NET 1.1, que carga un ensamblado desde este GAC compartido, podría obtener ensamblados .NET 2.0 , rompiendo así la aplicación .NET 1.1 ".
Max Toro
67

También quería saber por qué 2 GAC y encontré la siguiente explicación de Mark Miller en la sección de comentarios de .NET 4.0 tiene 2 Global Assembly Cache (GAC) :

Mark Miller dijo ... 28 de junio de 2010 12:13 PM

Gracias por la publicacion. Los "problemas de interferencia" fueron intencionalmente vagos. Al momento de escribir, los problemas aún se estaban investigando, pero estaba claro que había varios escenarios rotos.

Por ejemplo, algunas aplicaciones usan Assemby.LoadWithPartialName para cargar la versión más alta de un ensamblado. Si la versión más alta se compiló con v4, entonces una aplicación v2 (3.0 o 3.5) no podría cargarla, y la aplicación se bloquearía, incluso si hubiera una versión que hubiera funcionado. Originalmente, dividimos el GAC en su ubicación original, pero eso causó algunos problemas con los escenarios de actualización de Windows. Ambos implicaban código que ya se había enviado, por lo que trasladamos nuestro (GAC particionado en versión a otro lugar.

Esto no debería tener ningún impacto en la mayoría de las aplicaciones, y no agrega ninguna carga de mantenimiento. Solo se debe acceder o modificar ambas ubicaciones utilizando las API nativas de GAC, que se ocupan de la partición como se esperaba. Los lugares donde esto aparece son las API que exponen las rutas del GAC, como GetCachePath, o el examen de la ruta de mscorlib cargada en el código administrado.

Vale la pena señalar que modificamos las ubicaciones de GAC cuando lanzamos v2 también cuando presentamos la arquitectura como parte de la identidad del ensamblado. Esos agregaron GAC_MSIL, GAC_32 y GAC_64, aunque todos todavía están bajo% windir% \ assembly. Desafortunadamente, esa no era una opción para este lanzamiento.

Espero que ayude a los futuros lectores.

Jasl
fuente
3
Los comentarios de Miller sobre el artículo vinculado proporcionan una visión interna del tema.
Nimesh Madhavan
66

No tiene mucho sentido, el GAC original ya era bastante capaz de almacenar diferentes versiones de ensamblajes. Y hay pocas razones para suponer que un programa hará referencia accidentalmente al ensamblaje incorrecto, todos los ensamblados de .NET 4 obtuvieron la [Versión de ensamblaje] aumentada a 4.0.0.0. La nueva característica de proceso en paralelo no debería cambiar esto.

Mi suposición: ya había demasiados proyectos .NET que rompieron la regla de "nunca hacer referencia a nada en el GAC directamente". Lo he visto en este sitio varias veces.

Solo hay una forma de evitar romper esos proyectos: mover el GAC. Back-compat es sagrado en Microsoft.

Hans Passant
fuente
3
Esta es la única respuesta que intenta explicar por qué este es el caso. +1
Ed S.
1
@Hans Passant: ¿Qué quiere decir con "nunca hacer referencia a nada en el GAC directamente"?
Max Toro
2
@Max: hay dos copias de los ensamblados .NET en su máquina. Aquellos destinados a ser ensambles de referencia en c: \ windows \ microsoft.net y c: \ program files \ reference ensambles. Y los que se usan en tiempo de ejecución, el GAC @ c: \ windows \ assembly. No son lo mismo, 64 bits sería un ejemplo. Microsoft hizo todo lo posible para evitar que alguien haga referencia a los GAC con un controlador de extensión de shell. Y el cuadro de diálogo Agregar referencia. No es 100% efectivo
Hans Passant
@Hans Passant: Una referencia directa es algo así como 'c: \ WINDOWS \ assembly \ GAC_MSIL \ System \ 2.0.0.0__b77a5c561934e089 \ System.dll', no veo cómo agregar una nueva versión rompería esa referencia.
Max Toro
2
@Hans Passant: "Y hay pocas razones para suponer que un programa hará referencia accidental al ensamblaje incorrecto" Creo que la clave aquí es Assembly.LoadWithPartialName, ¿qué sucede si tenemos 2 versiones del ensamblaje en el GAC?
Max Toro