O .NET 4.0 possui um novo GAC, por quê?

300

%windir%\Microsoft.NET\assembly\é o novo GAC . Significa agora que precisamos gerenciar dois GACs, um para aplicativos .NET 2.0-3.5 e outro para aplicativos .NET 4.0?

A questão é, por quê?

Max Toro
fonte
7
obrigado por perguntar os question..i também estou muito confuso quando eu não encontrar GAC em seu local original :)
Jasl
2
Boa pergunta ... Muito obrigado.
smwikipedia
1
+1 para sua pergunta. Comecei o desenvolvimento no NET 4.0 e fiquei confuso com a questão "dupla" do GAC.
Hernán
3
Foram necessárias algumas iterações, mas a Microsoft finalmente trouxe o DLL Hell para o .NET. Yay!
Nothingisnecessary

Respostas:

181

Sim, como existem dois GACs (Global Assembly Cache) distintos, você precisará gerenciar cada um deles individualmente.

No .NET Framework 4.0, o GAC passou por algumas alterações. O GAC foi dividido em dois, um para cada CLR.

A versão do CLR usada para o .NET Framework 2.0 e o .NET Framework 3.5 é o CLR 2.0. Nas duas versões anteriores da estrutura, não havia necessidade de dividir o GAC. O problema de quebrar aplicativos mais antigos no Net Framework 4.0.

Para evitar problemas entre o CLR 2.0 e o CLR 4.0, o GAC agora é dividido em GACs privados para cada tempo de execução. A principal mudança é que os aplicativos CLR v2.0 agora não podem ver os assemblies do CLR v4.0 no GAC.

Fonte

Por quê?

Parece que houve uma alteração no CLR no .NET 4.0, mas não no 2.0 para 3.5. O mesmo aconteceu com o CLR 1.1 a 2.0. Parece que o GAC tem a capacidade de armazenar diferentes versões de montagens, desde que sejam do mesmo CLR. Eles não querem quebrar aplicativos antigos.

Consulte as seguintes informações no MSDN sobre as alterações do GAC na 4.0 .

Por exemplo, se o .NET 1.1 e o .NET 2.0 compartilharem o mesmo GAC, um aplicativo .NET 1.1, carregando um assembly desse GAC compartilhado, poderá obter os assemblies do .NET 2.0, quebrando o aplicativo .NET 1.1

A versão do CLR usada para o .NET Framework 2.0 e o .NET Framework 3.5 é o CLR 2.0. Como resultado disso, nas duas versões anteriores da estrutura não havia necessidade de dividir o GAC. O problema de quebrar aplicativos mais antigos (nesse caso, .NET 2.0) ressurge no Net Framework 4.0, momento em que o CLR 4.0 foi lançado. Portanto, para evitar problemas de interferência entre o CLR 2.0 e o CLR 4.0, o GAC agora é dividido em GACs privados para cada tempo de execução.

Como o CLR é atualizado em versões futuras, você pode esperar a mesma coisa. Se apenas o idioma mudar, você poderá usar o mesmo GAC.

Brian R. Bondy
fonte
18
Essa publicação do blog apenas reafirma a descoberta do OP, não explica por que o GAC precisava ser dividido. Não é óbvio, o GAC original teria sido capaz de manter os assemblies 4.0 separados. Eles têm um novo [AssemblyVersion]
Hans Passant
1
@ Hans: Talvez não seja o motivo exato, mas diz: "Para evitar problemas entre o CLR 2.0 e o CLR 4.0", também a pergunta tinha duas perguntas dentro dele. A segunda pergunta é: "significa que agora precisamos gerenciar dois GACs, um para aplicativos .NET 2.0-3.5 e outro para aplicativos .NET 4.0?"
Brian R. Bondy
2
Você deve citar isso, em um de seus links: "Por exemplo, se o .NET 1.1 e o .NET 2.0 compartilharem o mesmo GAC, um aplicativo .NET 1.1, carregando um assembly desse GAC compartilhado, poderá obter assemblies do .NET 2.0 , quebrando assim o aplicativo .NET 1.1. "
Max Toro
67

Eu também queria saber por que o 2 GAC e encontrei a seguinte explicação de Mark Miller no seção de comentários do .NET 4.0 tem 2 Global Assembly Cache (GAC) :

Mark Miller disse ... 28 de junho de 2010 12:13

Obrigado pelo post. "Problemas de interferência" eram intencionalmente vagos. No momento da redação deste artigo, os problemas ainda estavam sendo investigados, mas estava claro que havia vários cenários interrompidos.

Por exemplo, alguns aplicativos usam Assemby.LoadWithPartialName para carregar a versão mais alta de um assembly. Se a versão mais alta fosse compilada com a v4, um aplicativo da v2 (3.0 ou 3.5) não poderia carregá-lo e o aplicativo travaria, mesmo se houvesse uma versão que teria funcionado. Originalmente, particionamos o GAC sob o local original, mas isso causou alguns problemas nos cenários de atualização do Windows. Ambos envolviam o código que já havia sido enviado e, por isso, transferimos nosso (GAC particionado por versão) para outro local.

Isso não deve ter impacto na maioria dos aplicativos e não adiciona nenhum ônus de manutenção. Ambos os locais devem ser acessados ​​ou modificados apenas usando as APIs nativas do GAC, que lidam com o particionamento conforme o esperado. Os locais em que isso ocorre são as APIs que expõem os caminhos do GAC, como GetCachePath, ou examinam o caminho do mscorlib carregado no código gerenciado.

Vale a pena notar que modificamos os locais do GAC quando lançamos a v2 e quando introduzimos a arquitetura como parte da identidade do assembly. Eles adicionaram GAC_MSIL, GAC_32 e GAC_64, embora todos ainda estejam sob% windir% \ assembly. Infelizmente, essa não foi uma opção para este lançamento.

Espero que ajude futuros leitores.

Jasl
fonte
3
Os comentários de Miller no artigo vinculado fornecem uma visão privilegiada do tópico.
Nimesh Madhavan
66

Não faz muito sentido, o GAC original já era capaz de armazenar diferentes versões de assemblies. E há poucas razões para supor que um programa referencie acidentalmente o assembly errado, todos os assemblies do .NET 4 tiveram o [AssemblyVersion] aumentado para 4.0.0.0. O novo recurso lado a lado em processo não deve alterar isso.

Meu palpite: já havia muitos projetos .NET por aí que violavam a regra "nunca referenciar nada diretamente no GAC". Eu já vi isso neste site várias vezes.

Somente uma maneira de evitar a quebra desses projetos: mova o GAC. A compatibilidade com as costas é sagrada na Microsoft.

Hans Passant
fonte
3
Essa é a única resposta que tenta explicar por que esse é o caso. +1
Ed S.
1
@ Hans Passant: O que você quer dizer com regra "nunca referenciar nada diretamente no GAC"?
Max Toro
2
@ Max: existem duas cópias dos assemblies .NET em sua máquina. Aqueles destinados a serem assemblies de referência em assemblies c: \ windows \ microsoft.net e c: \ arquivos de programas \ assemblies de referência. E os usados ​​em tempo de execução, o GAC @ c: \ windows \ assembly. Eles não são os mesmos, 64 bits seria um exemplo. A Microsoft fez o possível para evitar que alguém fizesse referência aos do GAC com um manipulador de extensão de shell. E a caixa de diálogo Adicionar referência. Não é 100% eficaz
Hans Passant
@ Hans Passant: Uma referência direta é algo como 'c: \ WINDOWS \ assembly \ GAC_MSIL \ System \ 2.0.0.0__b77a5c561934e089 \ System.dll', não vejo como adicionar uma nova versão quebraria essa referência.
Max Toro
2
@Hans Passant: "E há poucas razões para supor que um programa fará referência acidental à montagem errada". Acho que a chave aqui é Assembly.LoadWithPartialName: o que acontece se tivermos duas versões da montagem no GAC?
Max Toro às