Quais são as diferenças entre AssemblyVersion, AssemblyFileVersion e AssemblyInformationalVersion?

860

Existem três atributos de versão de montagem. O que são diferenças? Tudo bem se eu usar AssemblyVersione ignorar o resto?


MSDN diz:

  • AssemblyVersion :

    Especifica a versão da montagem que está sendo atribuída.

  • AssemblyFileVersion :

    Instrui um compilador a usar um número de versão específico para o recurso de versão do arquivo Win32. A versão do arquivo Win32 não precisa ser igual ao número da versão do assembly.

  • AssemblyInformationalVersion :

    Define informações adicionais da versão para um manifesto de montagem.


Este é um acompanhamento de Quais são as melhores práticas para usar Atributos de Montagem?

Jakub Šturc
fonte

Respostas:

907

AssemblyVersion

Onde serão exibidas as outras montagens que fazem referência à sua montagem. Se esse número for alterado, outros assemblies precisarão atualizar suas referências para o assembly! Atualize esta versão apenas se ela quebrar a compatibilidade com versões anteriores. O AssemblyVersioné obrigatório.

Eu uso o formato: major.minor . Isso resultaria em:

[assembly: AssemblyVersion("1.0")]

Se você seguir rigorosamente o SemVer , isso significa que você só atualizará quando as principais mudanças forem alteradas, portanto 1.0, 2.0, 3.0 etc.

AssemblyFileVersion

Usado para implantação. Você pode aumentar esse número para cada implantação. É usado por programas de instalação. Use-o para marcar montagens que tenham o mesmoAssemblyVersion , mas são geradas a partir de diferentes compilações.

No Windows, ele pode ser exibido nas propriedades do arquivo.

O AssemblyFileVersion é opcional. Se não for fornecido, o AssemblyVersion é usado.

Eu uso o formato: major.minor.patch.build , onde sigo o SemVer nas três primeiras partes e uso o número de compilação do servidor de compilação para a última parte (0 para compilação local). Isso resultaria em:

[assembly: AssemblyFileVersion("1.3.2.254")]

Esteja ciente de que System.Version nomeia essas partes como major.minor.build.revision!

AssemblyInformationalVersion

A versão do produto da montagem. Esta é a versão que você usaria ao conversar com os clientes ou para exibição no seu site. Esta versão pode ser uma string, como ' 1.0 Release Candidate '.

O AssemblyInformationalVersioné opcional. Se não for fornecido, o AssemblyFileVersion é usado.

Eu uso o formato: major.minor [.patch] [revisão como string] . Isso resultaria em:

[assembly: AssemblyInformationalVersion("1.0 RC1")]
Rémy van Duijkeren
fonte
4
Para AssemblyFileVersion, "Se possível, deixe que seja gerado pelo MSBuild" - Por quê? Você acabou de explicar um bom motivo para controlá-lo manualmente :)
mo.
3
O aviso no formato AssemblyInformationalVersion ainda existe no VS2010 hoje (21 de maio de 2013) e seu link está inoperante.
Reinierpost
22
Infelizmente, a Classe de Versão define major.minor[.build[.revision]]e não major.minor.revision.buildna resposta fornecida os números de construção e revisão seriam trocados se você estivesse usando as propriedades da classe ou System.Reflection.Assembly.GetExecutingAssembly().GetName().Versionpara detectar os números de construção e revisão.
thinkOfaNumber 21/01
9
@thinkOfaNumber Você está certo sobre a classe Version, mas esse é o modo de versão da Microsoft. Pessoalmente, acho estranho não ter o número de compilação no final e é por isso que apenas coloquei meu formato como exemplo, com base no Semantic Versioning . Você é livre para usar o caminho da Microsoft ou o seu próprio caminho, é claro.
Rémy van Duijkeren
6
Deve-se notar que AssemblyInformationalVersion, se omitido, AssemblyFileVersioné usado. Então, AssemblyVersion se ambos são omitidos.
Drazen Bjelovuk
588

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 AssemblyFileVersionobjetivo é 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 AssemblyVersiondeve 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!

Daniel Fortunov
fonte
9
Ótima resposta. Acho que o ponto mais importante que você fez - e o que a MS deveria recomendar explicitamente - é fazer alterações na AssemblyVersion se e somente se a nova versão quebrar a compatibilidade com versões anteriores.
Mkolfe02
1
Uma das perguntas que me faço repetidamente é: quando devo alterar cada um desses números de versão, seus pontos no AssemblyVersion adicionaram uma boa clareza a isso e toda a resposta foi uma leitura interessante.
RyanfaeScotland
Estou vendo muitas respostas que explicam os conceitos por trás dessas três coisas. Mas como eles se relacionam com os números de versão editáveis ​​nas propriedades do projeto? Ao clicar em Informações da montagem ..., você tem a opção de alterar duas versões. E alterar a versão do assembly altera a pasta onde o user.config é encontrado e alterar a versão do arquivo altera o número da versão mostrada quando você clica com o botão direito do mouse no arquivo exe e acessa suas propriedades. Então, como esses dois números de versão correspondem a AssemblyVersion, AssemblyFileVersion e AssemblyInformationalVersion?
Kyle Delaney
O link para a postagem do blog que você escreveu originalmente fornece um 404. Existe um novo local para isso?
Rob K
@RobK: Ah, desculpas. Esse site está fora do ar, mas todo o conteúdo da postagem do blog é reproduzido na resposta para que você não perca nada. Vou remover o link quebrado agora.
Daniel Fortunov
43

AssemblyVersionpraticamente permanece interno ao .NET, enquanto AssemblyFileVersioné o que o Windows vê. Se você acessar as propriedades de uma montagem em um diretório e alternar para a guia versão, AssemblyFileVersioné isso que verá no topo. Se você classificar arquivos por versão, é isso que é usado pelo Explorer.

Os AssemblyInformationalVersionmapas para a "Versão do produto" devem ser puramente "usados ​​por humanos".

AssemblyVersioné certamente o mais importante, mas eu também não pularia AssemblyFileVersion. Se você não fornecer AssemblyInformationalVersion, o compilador o adicionará removendo a parte "revisão" do número da sua versão e saindo do major.minor.build.

Bob King
fonte
23

AssemblyInformationalVersione AssemblyFileVersionsão exibidos quando você exibe as informações de "Versão" em um arquivo através do Windows Explorer, visualizando as propriedades do arquivo. Na verdade, esses atributos são compilados em um VERSION_INFOrecurso criado pelo compilador.

AssemblyInformationalVersion é o valor "Versão do produto". AssemblyFileVersioné o valor "Versão do arquivo".

A AssemblyVersioné específico para .NET conjuntos e é usada pelo carregador .NET montagem para saber qual a versão de um conjunto de carga / ligamento no tempo de execução.

Destes, o único que é absolutamente exigido pelo .NET é o AssemblyVersionatributo Infelizmente, também pode causar o maior número de problemas quando muda indiscriminadamente, especialmente se você é forte em nomear suas assembléias.

Scott Dorman
fonte
9

Para manter essa pergunta atualizada, vale destacar o que AssemblyInformationalVersioné usado pelo NuGet e reflete a versão do pacote incluindo qualquer sufixo de pré-lançamento.

Por exemplo, um AssemblyVersion de 1.0.3. * Empacotado com o asp.net core dotnet-cli

dotnet pack --version-suffix ci-7 src/MyProject

Produz um pacote com a versão 1.0.3-ci-7 que você pode inspecionar com reflexão usando:

CustomAttributeExtensions.GetCustomAttribute<AssemblyInformationalVersionAttribute>(asm);
KCD
fonte
7

Vale a pena notar algumas outras coisas:

1) Como mostrado na caixa de diálogo Propriedades do Windows Explorer para o arquivo de montagem gerado, existem dois locais chamados "Versão do arquivo". A vista no cabeçalho da caixa de diálogo mostra AssemblyVersion, não AssemblyFileVersion.

Na seção Outras informações sobre a versão, há outro elemento chamado "Versão do arquivo". É aqui que você pode ver o que foi inserido como AssemblyFileVersion.

2) AssemblyFileVersion é apenas texto simples. Ele não precisa estar em conformidade com as restrições do esquema de numeração que o AssemblyVersion faz (<build> <65K, por exemplo). Pode ser 3.2. <Release tag text>. <datetime>, se desejar. Seu sistema de compilação precisará preencher os tokens.

Além disso, não está sujeito à substituição de curinga que AssemblyVersion é. Se você tiver apenas o valor "3.0.1. *" No AssemblyInfo.cs, é exatamente isso que será exibido no elemento Outras informações da versão-> Versão do arquivo.

3) No entanto, não sei o impacto sobre um instalador de usar algo diferente de números de versão numérica do arquivo.

DavidM
fonte
2

Quando o AssemblyVersion de um assembly é alterado, se ele tiver um nome forte, os assemblies de referência precisam ser recompilados, caso contrário, o assembly não será carregado! Se ele não tiver um nome forte, se não for explicitamente adicionado ao arquivo do projeto, ele não será copiado para o diretório de saída durante a compilação, para que você possa perder as montagens, principalmente após limpar o diretório de saída.

ceder
fonte
Isto é muito interessante! Você poderia elaborar um pouco sobre a parte "não será copiada para o diretório de saída"? Talvez um link para onde esse comportamento é definido. Nunca entendi por que algumas dependências indiretas eram copiadas às vezes, mas nem sempre. Isso deve estar 100% relacionado a isso.
julealgon