O controle de versão de assemblies no .NET pode ser uma perspectiva confusa, pois atualmente há pelo menos três maneiras de especificar uma versão para seu assembly.
Aqui estão os três principais atributos de montagem relacionados à versão:
// Assembly mscorlib, Version 2.0.0.0
[assembly: AssemblyFileVersion("2.0.50727.3521")]
[assembly: AssemblyInformationalVersion("2.0.50727.3521")]
[assembly: AssemblyVersion("2.0.0.0")]
Por convenção, as quatro partes da versão são chamadas de versão principal , versão secundária , compilação e revisão .
O AssemblyFileVersion
objetivo é identificar exclusivamente uma construção da montagem individual
Normalmente, você define manualmente o AssemblyFileVersion Maior e Menor para refletir a versão do assembly, depois incrementa a Compilação e / ou Revisão toda vez que seu sistema de compilação compila o assembly. O AssemblyFileVersion deve permitir identificar exclusivamente uma compilação do assembly, para que você possa usá-lo como ponto de partida para depurar qualquer problema.
No meu projeto atual, o servidor de construção codifica o número da lista de alterações do nosso repositório de controle de origem nas partes Build e Revisão da AssemblyFileVersion. Isso nos permite mapear diretamente de um assembly para seu código-fonte, para qualquer assembly gerado pelo servidor de compilação (sem a necessidade de usar etiquetas ou ramificações no controle de origem ou manter manualmente os registros das versões lançadas).
Esse número de versão é armazenado no recurso de versão do Win32 e pode ser visto ao exibir as páginas de propriedades do Windows Explorer para o assembly.
O CLR não se importa nem examina a AssemblyFileVersion.
o AssemblyInformationalVersion
objetivo é representar a versão de todo o seu produto
O AssemblyInformationalVersion destina-se a permitir a versão coerente de todo o produto, que pode consistir em muitos assemblies com versão independente, talvez com políticas de versão diferentes e potencialmente desenvolvidos por equipes diferentes.
“Por exemplo, a versão 2.0 de um produto pode conter vários conjuntos; um desses assemblies é marcado como versão 1.0, pois é um novo assembly que não foi enviado na versão 1.0 do mesmo produto. Normalmente, você define as partes principais e secundárias deste número de versão para representar a versão pública do seu produto. Depois, você incrementa as peças de construção e revisão cada vez que empacota um produto completo com todos os seus conjuntos. ” - Jeffrey Richter, [CLR via C # (segunda edição)] p. 57
O CLR não se importa nem examina a AssemblyInformationalVersion.
o AssemblyVersion
é a única versão com a qual o CLR se preocupa (mas se preocupa com o todo AssemblyVersion
)
O AssemblyVersion é usado pelo CLR para vincular a assemblies fortemente nomeados. Ele é armazenado na tabela de metadados do manifesto AssemblyDef do assembly criado e na tabela AssemblyRef de qualquer assembly que faça referência a ele.
Isso é muito importante, porque significa que, quando você faz referência a um assembly com nome forte, está fortemente vinculado a uma AssemblyVersion específica desse assembly. O AssemblyVersion inteiro deve ser uma correspondência exata para que a ligação seja bem-sucedida. Por exemplo, se você referenciar a versão 1.0.0.0 de um assembly com nome forte no momento da construção, mas apenas a versão 1.0.0.1 desse assembly estiver disponível no tempo de execução, a ligação falhará! (Você precisará contornar isso usando o redirecionamento de associação de montagem .)
Confusão sobre se o todo AssemblyVersion
deve corresponder. (Sim.)
Há um pouco de confusão sobre se a AssemblyVersion inteira deve ser uma correspondência exata para que um assembly seja carregado. Algumas pessoas estão sob a falsa crença de que apenas as partes Maior e Menor da AssemblyVersion precisam corresponder para que a ligação seja bem-sucedida. Essa é uma suposição sensata, no entanto, no final das contas, está incorreta (a partir do .NET 3.5) e é trivial verificar isso na sua versão do CLR. Basta executar este código de exemplo .
Na minha máquina, a segunda carga de montagem falha e as duas últimas linhas do log de fusão deixam perfeitamente claro o motivo:
.NET Framework Version: 2.0.50727.3521
---
Attempting to load assembly: Rhino.Mocks, Version=3.5.0.1337, Culture=neutral, PublicKeyToken=0b3305902db7183f
Successfully loaded assembly: Rhino.Mocks, Version=3.5.0.1337, Culture=neutral, PublicKeyToken=0b3305902db7183f
---
Attempting to load assembly: Rhino.Mocks, Version=3.5.0.1336, Culture=neutral, PublicKeyToken=0b3305902db7183f
Assembly binding for failed:
System.IO.FileLoadException: Could not load file or assembly 'Rhino.Mocks, Version=3.5.0.1336, Culture=neutral,
PublicKeyToken=0b3305902db7183f' or one of its dependencies. The located assembly's manifest definition
does not match the assembly reference. (Exception from HRESULT: 0x80131040)
File name: 'Rhino.Mocks, Version=3.5.0.1336, Culture=neutral, PublicKeyToken=0b3305902db7183f'
=== Pre-bind state information ===
LOG: User = Phoenix\Dani
LOG: DisplayName = Rhino.Mocks, Version=3.5.0.1336, Culture=neutral, PublicKeyToken=0b3305902db7183f
(Fully-specified)
LOG: Appbase = [...]
LOG: Initial PrivatePath = NULL
Calling assembly : AssemblyBinding, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null.
===
LOG: This bind starts in default load context.
LOG: No application configuration file found.
LOG: Using machine configuration file from C:\Windows\Microsoft.NET\Framework64\v2.0.50727\config\machine.config.
LOG: Post-policy reference: Rhino.Mocks, Version=3.5.0.1336, Culture=neutral, PublicKeyToken=0b3305902db7183f
LOG: Attempting download of new URL [...].
WRN: Comparing the assembly name resulted in the mismatch: Revision Number
ERR: Failed to complete setup of assembly (hr = 0x80131040). Probing terminated.
Eu acho que a fonte dessa confusão é provavelmente porque a Microsoft originalmente pretendia ser um pouco mais tolerante com essa correspondência estrita da AssemblyVersion completa, correspondendo apenas nas partes das versões Maior e Menor:
“Ao carregar uma montagem, o CLR encontrará automaticamente a versão de serviço instalada mais recente que corresponde à versão principal / secundária da montagem que está sendo solicitada.” - Jeffrey Richter, [CLR via C # (segunda edição)] p. 56.
Esse era o comportamento do Beta 1 do 1.0 CLR, no entanto, esse recurso foi removido antes da versão 1.0 e não conseguiu voltar à tona no .NET 2.0:
“Nota: Acabei de descrever como você deve pensar nos números das versões. Infelizmente, o CLR não trata os números de versão dessa maneira. [No .NET 2.0], o CLR trata um número de versão como um valor opaco e, se um assembly depende da versão 1.2.3.4 de outro assembly, o CLR tenta carregar apenas a versão 1.2.3.4 (a menos que um redirecionamento de ligação esteja em vigor ) No entanto
Microsoft planeja alterar o carregador do CLR em uma versão futura para carregar a versão / versão mais recente de uma determinada versão principal / secundária de um assembly,. Por exemplo, em uma versão futura do CLR, se o carregador estiver tentando encontrar a versão 1.2.3.4 de uma montagem e a versão 1.2.5.0, o carregador buscará automaticamente a versão de serviço mais recente. Esta será uma mudança muito bem-vinda ao carregador do CLR - eu mal posso esperar. ” - Jeffrey Richter, [CLR via C # (segunda edição)] p. 164 (ênfase minha)
Como essa mudança ainda não foi implementada, acho seguro presumir que a Microsoft tenha rastreado essa intenção e talvez seja tarde demais para mudar isso agora. Tentei pesquisar na web para descobrir o que aconteceu com esses planos, mas não consegui encontrar respostas. Eu ainda queria chegar ao fundo disso.
Então, enviei um e-mail para Jeff Richter e perguntei diretamente a ele - imaginei que se alguém soubesse o que aconteceu, seria ele.
Ele respondeu dentro de 12 horas, em uma manhã de sábado, e esclareceu que o carregador .NET 1.0 Beta 1 implementou esse mecanismo de 'rollforward automático' para captar a última versão disponível de compilação e revisão de uma montagem, mas esse comportamento era revertida antes do .NET 1.0 enviado. Mais tarde, pretendia reviver isso, mas não chegou antes do lançamento do CLR 2.0. Depois veio o Silverlight, que tinha prioridade para a equipe de CLR, e essa funcionalidade foi adiada. Enquanto isso, a maioria das pessoas que estavam por aí nos dias de CLR 1.0 Beta 1 desde então seguiu em frente, então é improvável que isso aconteça, apesar de todo o trabalho árduo que já havia sido feito.
O comportamento atual, ao que parece, chegou para ficar.
Também vale a pena notar na minha discussão com Jeff que o AssemblyFileVersion só foi adicionado após a remoção do mecanismo de 'rollforward automático' - porque, após a versão 1.0 Beta 1, qualquer alteração no AssemblyVersion era uma alteração de ruptura para seus clientes. nenhum lugar para armazenar com segurança seu número de compilação. AssemblyFileVersion é esse porto seguro, pois nunca é examinado automaticamente pelo CLR. Talvez seja mais claro assim, ter dois números de versão separados, com significados separados, em vez de tentar fazer essa separação entre as partes Maior / Menor (quebra) e a Construção / Revisão (sem quebra) da AssemblyVersion.
Conclusão: pense com cuidado quando alterar sua AssemblyVersion
A moral é que, se você estiver enviando assemblies que outros desenvolvedores farão referência, precisará ser extremamente cuidadoso quando alterar (e não) a AssemblyVersion desses assemblies. Quaisquer alterações no AssemblyVersion significarão que os desenvolvedores de aplicativos precisarão recompilar com a nova versão (para atualizar essas entradas AssemblyRef) ou usar redirecionamentos de ligação de assembly para substituir manualmente a ligação.
- Não altere a AssemblyVersion para uma liberação de manutenção que seja compatível com versões anteriores.
- Não mudar o AssemblyVersion para um lançamento que você conhece tem alterações significativas.
Basta dar uma olhada nos atributos de versão no mscorlib:
// Assembly mscorlib, Version 2.0.0.0
[assembly: AssemblyFileVersion("2.0.50727.3521")]
[assembly: AssemblyInformationalVersion("2.0.50727.3521")]
[assembly: AssemblyVersion("2.0.0.0")]
Observe que é o AssemblyFileVersion que contém todas as informações interessantes sobre manutenção (é a parte Revisão desta versão que informa em qual Service Pack você está), enquanto o AssemblyVersion está corrigido em um 2.0.0.0 antigo e chato. Qualquer alteração no AssemblyVersion forçaria todos os aplicativos .NET que fazem referência ao mscorlib.dll a recompilar com a nova versão!