Quelles sont les différences entre AssemblyVersion, AssemblyFileVersion et AssemblyInformationalVersion?

860

Il existe trois attributs de version d'assembly. Quelles sont les différences? Est-ce correct si j'utilise AssemblyVersionet ignore le reste?


MSDN dit:

  • AssemblyVersion :

    Spécifie la version de l'assembly en cours d'attribution.

  • AssemblyFileVersion :

    Demande à un compilateur d'utiliser un numéro de version spécifique pour la ressource de version de fichier Win32. Il n'est pas nécessaire que la version du fichier Win32 soit identique au numéro de version de l'assembly.

  • AssemblyInformationalVersion :

    Définit des informations de version supplémentaires pour un manifeste d'assembly.


Ceci fait suite à Quelles sont les meilleures pratiques d'utilisation des attributs d'assemblage?

Jakub Šturc
la source

Réponses:

907

AssemblyVersion

Où les autres assemblys qui référencent votre assemblage vont chercher. Si ce nombre change, les autres assemblages doivent mettre à jour leurs références à votre assemblage! Ne mettez à jour cette version que si elle rompt la compatibilité descendante. Le AssemblyVersionest obligatoire.

J'utilise le format: major.minor . Il en résulterait:

[assembly: AssemblyVersion("1.0")]

Si vous suivez SemVer strictement, cela signifie que vous ne mettez à jour que lorsque les modifications majeures , 1.0, 2.0, 3.0, etc.

AssemblyFileVersion

Utilisé pour le déploiement. Vous pouvez augmenter ce nombre pour chaque déploiement. Il est utilisé par les programmes d'installation. Utilisez-le pour marquer les assemblys qui ont les mêmes AssemblyVersion, mais qui sont générés à partir de versions différentes.

Sous Windows, il peut être consulté dans les propriétés du fichier.

AssemblyFileVersion est facultatif. S'il n'est pas donné, AssemblyVersion est utilisé.

J'utilise le format: major.minor.patch.build , où je suis SemVer pour les trois premières parties et utilise le numéro de build du buildserver pour la dernière partie (0 pour la construction locale). Il en résulterait:

[assembly: AssemblyFileVersion("1.3.2.254")]

Sachez que System.Version nomme ces pièces major.minor.build.revision!

AssemblyInformationalVersion

La version du produit de l'assemblage. Il s'agit de la version que vous utiliseriez pour parler aux clients ou pour l'affichage sur votre site Web. Cette version peut être une chaîne, comme « 1.0 Release Candidate ».

Le AssemblyInformationalVersionest facultatif. S'il n'est pas donné, AssemblyFileVersion est utilisé.

J'utilise le format: major.minor [.patch] [révision comme chaîne] . Il en résulterait:

[assembly: AssemblyInformationalVersion("1.0 RC1")]
Rémy van Duijkeren
la source
4
Pour AssemblyFileVersion, «Si possible, laissez-le être généré par MSBuild» - Pourquoi? Vous venez d'expliquer une bonne raison de le contrôler manuellement :)
mo.
3
L'avertissement sur le format AssemblyInformationalVersion existe toujours dans VS2010 aujourd'hui (21 mai 2013) et votre lien est mort.
reinierpost
22
Malheureusement, la classe de version définit major.minor[.build[.revision]]et pas major.minor.revision.buildainsi dans la réponse donnée, les numéros de version et de révision seraient échangés si vous utilisiez les propriétés de la classe ou System.Reflection.Assembly.GetExecutingAssembly().GetName().Versionpour détecter les numéros de version et de révision.
thinkOfaNumber
9
@thinkOfaNumber Votre droit sur la classe de version, mais c'est la manière de Microsoft de versionner. Personnellement, je pense qu'il est étrange de ne pas avoir le numéro de build à la fin et c'est pourquoi je ne mets que mon format comme exemple, basé sur le versionnage sémantique . Votre libre d'utiliser la manière Microsoft ou votre propre façon bien sûr.
Rémy van Duijkeren
6
Il convient de noter que pour AssemblyInformationalVersion, s'il est omis, AssemblyFileVersionest utilisé. Ensuite, AssemblyVersion si les deux sont omis.
Drazen Bjelovuk
588

Le versionnement des assemblys dans .NET peut être une perspective déroutante étant donné qu'il existe actuellement au moins trois façons de spécifier une version pour votre assembly.

Voici les trois principaux attributs d'assembly liés à la version:

// 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")]

Par convention, les quatre parties de la version sont appelés la version majeure , version mineure , Construire et révision .

Le AssemblyFileVersionest destiné à identifier de manière unique une version de l' assemblage individuel

En règle générale, vous définissez manuellement les versions AssemblyFile Major et Minor pour refléter la version de l'assembly, puis incrémentez la génération et / ou la révision à chaque fois que votre système de build compile l'assembly. AssemblyFileVersion doit vous permettre d'identifier de manière unique une génération de l'assembly, afin que vous puissiez l'utiliser comme point de départ pour déboguer tout problème.

Sur mon projet actuel, le serveur de génération code le numéro de liste de modifications de notre référentiel de contrôle de source dans les parties Build et Revision de AssemblyFileVersion. Cela nous permet de mapper directement d'un assembly à son code source, pour tout assembly généré par le serveur de build (sans avoir à utiliser des étiquettes ou des branches dans le contrôle de code source, ou à conserver manuellement les enregistrements des versions publiées).

Ce numéro de version est stocké dans la ressource de version Win32 et peut être vu lors de l'affichage des pages de propriétés de l'Explorateur Windows pour l'assembly.

Le CLR ne se soucie ni n'examine la AssemblyFileVersion.

Le AssemblyInformationalVersionest destiné à représenter la version de l'ensemble de votre produit

AssemblyInformationalVersion est destiné à permettre un versionnage cohérent de l'ensemble du produit, qui peut être composé de nombreux assemblys qui sont versionnés indépendamment, peut-être avec des politiques de versioning différentes, et potentiellement développés par des équipes disparates.

«Par exemple, la version 2.0 d'un produit peut contenir plusieurs assemblages; l'un de ces assemblages est marqué comme version 1.0 car il s'agit d'un nouvel assemblage qui n'a pas été livré dans la version 1.0 du même produit. En règle générale, vous définissez les parties principales et mineures de ce numéro de version pour représenter la version publique de votre produit. Ensuite, vous incrémentez les parties de construction et de révision chaque fois que vous conditionnez un produit complet avec tous ses assemblages. » - Jeffrey Richter, [CLR via C # (deuxième édition)] p. 57

Le CLR ne se soucie pas ni n'examine la AssemblyInformationalVersion.

C'est AssemblyVersionla seule version dont le CLR se soucie (mais il se soucie de l'ensemble AssemblyVersion)

AssemblyVersion est utilisé par le CLR pour se lier à des assemblys fortement nommés. Il est stocké dans la table de métadonnées du manifeste AssemblyDef de l'assembly généré et dans la table AssemblyRef de tout assembly qui le référence.

Ceci est très important, car cela signifie que lorsque vous référencez un assemblage fortement nommé, vous êtes étroitement lié à une version d'assemblage spécifique de cet assemblage. L'ensemble AssemblyVersion doit être une correspondance exacte pour que la liaison réussisse. Par exemple, si vous référencez la version 1.0.0.0 d'un assembly fortement nommé au moment de la construction, mais que seule la version 1.0.0.1 de cet assembly est disponible au moment de l'exécution, la liaison échouera! (Vous devrez ensuite contourner ce problème en utilisant la redirection de liaison d'assembly .)

Confusion quant à savoir si l'ensemble AssemblyVersiondoit correspondre. (Oui.)

Il existe une petite confusion quant à savoir si l'ensemble AssemblyVersion doit être une correspondance exacte pour qu'un assemblage soit chargé. Certaines personnes croient à tort que seules les parties majeures et mineures de la version Assembly doivent correspondre pour que la liaison réussisse. Il s'agit d'une hypothèse raisonnable, mais elle est finalement incorrecte (à partir de .NET 3.5), et il est trivial de vérifier cela pour votre version du CLR. Exécutez simplement cet exemple de code .

Sur ma machine, la deuxième charge d'assemblage échoue et les deux dernières lignes du journal de fusion expliquent parfaitement pourquoi:

.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.

Je pense que la source de cette confusion est probablement due au fait que Microsoft avait initialement l'intention d'être un peu plus indulgent sur cette correspondance stricte de la version complète de AssemblyVersion, en ne faisant correspondre que les parties des versions Major et Minor:

"Lors du chargement d'un assemblage, le CLR trouvera automatiquement la dernière version de maintenance installée qui correspond à la version principale / mineure de l'assemblage demandé." - Jeffrey Richter, [CLR via C # (deuxième édition)] p. 56

C'était le comportement de la version bêta 1 du CLR 1.0, mais cette fonctionnalité a été supprimée avant la version 1.0 et n'a pas réussi à refaire surface dans .NET 2.0:

«Remarque: je viens de décrire comment vous devriez penser aux numéros de version. Malheureusement, le CLR ne traite pas les numéros de version de cette façon. [Dans .NET 2.0], le CLR traite un numéro de version comme une valeur opaque et si un assembly dépend de la version 1.2.3.4 d'un autre assembly, le CLR essaie de charger la version 1.2.3.4 uniquement (sauf si une redirection de liaison est en place ). Cependant, Microsoft prévoit de modifier le chargeur du CLR dans une future version afin qu'il charge la dernière version / révision pour une version majeure / mineure donnée d'un assemblage. Par exemple, sur une future version du CLR, si le chargeur essaie de trouver la version 1.2.3.4 d'un assemblage et que la version 1.2.5.0 existe, le chargeur récupère automatiquement la dernière version de maintenance. Ce sera un changement très apprécié dans le chargeur du CLR - pour ma part, je ne peux pas attendre. » - Jeffrey Richter, [CLR via C # (deuxième édition)] p. 164 (c'est moi qui souligne)

Comme ce changement n'a toujours pas été mis en œuvre, je pense qu'il est prudent de supposer que Microsoft a fait marche arrière sur cette intention, et il est peut-être trop tard pour changer cela maintenant. J'ai essayé de chercher sur le Web pour savoir ce qui s'est passé avec ces plans, mais je n'ai trouvé aucune réponse. Je voulais toujours aller au fond des choses.

J'ai donc envoyé un courriel à Jeff Richter et lui ai demandé directement - je me suis dit que si quelqu'un savait ce qui s'était passé, ce serait lui.

Il a répondu dans les 12 heures, un samedi matin au moins, et a précisé que le chargeur .NET 1.0 Beta 1 avait mis en œuvre ce mécanisme de `` roll-forward automatique '' pour récupérer la dernière version disponible de la construction et de la révision d'un assemblage, mais ce comportement était rétabli avant l'expédition de .NET 1.0. Il était plus tard destiné à faire revivre cela, mais il n'a pas réussi avant la livraison du CLR 2.0. Puis vint Silverlight, qui était prioritaire pour l'équipe CLR, cette fonctionnalité a donc été retardée davantage. Entre-temps, la plupart des gens qui étaient là à l'époque de CLR 1.0 Beta 1 ont depuis évolué, il est donc peu probable que cela voit le jour, malgré tout le travail acharné qui a déjà été fait.

Il semble que le comportement actuel soit là pour rester.

Il est également intéressant de noter de ma discussion avec Jeff que AssemblyFileVersion n'a été ajouté qu'après la suppression du mécanisme de `` roll-forward automatique '' - car après 1.0 Beta 1, toute modification de AssemblyVersion était un changement de rupture pour vos clients, il y avait alors nulle part où stocker votre numéro de build en toute sécurité. AssemblyFileVersion est ce refuge, car il n'est jamais automatiquement examiné par le CLR. Peut-être que c'est plus clair de cette façon, avoir deux numéros de version séparés, avec des significations distinctes, plutôt que d'essayer de faire cette séparation entre les parties Majeure / Mineure (rupture) et Build / Révision (non cassante) de AssemblyVersion.

En bout de ligne: Réfléchissez bien lorsque vous modifiez votre AssemblyVersion

La morale est que si vous expédiez des assemblys auxquels d'autres développeurs vont faire référence, vous devez être extrêmement prudent lorsque vous modifiez (et ne modifiez pas) la version d'assembly de ces assemblys. Toute modification apportée à AssemblyVersion signifie que les développeurs d'applications devront soit recompiler la nouvelle version (pour mettre à jour ces entrées AssemblyRef), soit utiliser des redirections de liaison d'assembly pour remplacer manuellement la liaison.

  • Ne modifiez pas AssemblyVersion pour une version de maintenance destinée à être rétrocompatible.
  • Modifiez AssemblyVersion pour une version dont vous savez qu'elle comporte des modifications importantes.

Jetez un coup d'œil aux attributs de version sur 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")]

Notez que c'est le AssemblyFileVersion qui contient toutes les informations de maintenance intéressantes (c'est la partie Révision de cette version qui vous indique sur quel Service Pack vous êtes), tandis que le AssemblyVersion est fixé à un ancien ennuyeux 2.0.0.0. Toute modification apportée à AssemblyVersion forcerait chaque application .NET référençant mscorlib.dll à recompiler avec la nouvelle version!

Daniel Fortunov
la source
9
Très bonne réponse. Je pense que le point le plus important que vous avez fait valoir - et ce que MS devrait recommander explicitement - est d'apporter des modifications à AssemblyVersion si et seulement si la nouvelle version rompt la compatibilité descendante.
mwolfe02
1
L'une des questions que je me pose à plusieurs reprises est de savoir quand dois-je changer chacun de ces numéros de version, vos puces sur AssemblyVersion ont ajouté une bonne clarté à cela et la réponse entière a été une lecture intéressante.
RyanfaeScotland
Je vois beaucoup de réponses qui expliquent les concepts derrière ces trois choses. Mais comment sont-ils liés aux numéros de version modifiables dans les propriétés du projet? Lorsque vous cliquez sur Assembly Information ... vous avez la possibilité de modifier deux versions. Et la modification de la version de l'assembly modifie le dossier où se trouve user.config, et la modification de la version du fichier modifie le numéro de version affiché lorsque vous cliquez avec le bouton droit sur le fichier exe et accédez à ses propriétés. Alors, comment ces deux numéros de version correspondent-ils à AssemblyVersion, AssemblyFileVersion et AssemblyInformationalVersion?
Kyle Delaney du
Le lien vers le blog que vous avez écrit à l'origine donne un 404. Y a-t-il un nouvel emplacement pour cela?
Rob K
@RobK: Ah, toutes mes excuses. Ce site Web est en panne, mais tout le contenu de l'article de blog est reproduit dans la réponse afin que vous ne manquiez de rien. Je vais supprimer le lien cassé maintenant.
Daniel Fortunov
43

AssemblyVersionreste à peu près interne à .NET, alors AssemblyFileVersionque Windows le voit. Si vous accédez aux propriétés d'un assemblage situé dans un répertoire et passez à l'onglet version, AssemblyFileVersionc'est ce que vous verrez en haut. Si vous triez les fichiers par version, c'est ce qui est utilisé par Explorer.

Les AssemblyInformationalVersioncartes correspondent à la "version du produit" et sont destinées à être purement "utilisées par l'homme".

AssemblyVersionest certainement le plus important, mais je ne sauterais pas non AssemblyFileVersionplus. Si vous ne fournissez pas AssemblyInformationalVersion, le compilateur l'ajoute pour vous en supprimant la partie "révision" de votre numéro de version et en laissant le major.minor.build.

Bob King
la source
23

AssemblyInformationalVersionet AssemblyFileVersions'affichent lorsque vous affichez les informations "Version" sur un fichier via l'Explorateur Windows en affichant les propriétés du fichier. Ces attributs sont en fait compilés dans une VERSION_INFOressource créée par le compilateur.

AssemblyInformationalVersionest la valeur "Version du produit". AssemblyFileVersionest la valeur "Version du fichier".

Le AssemblyVersionest spécifique aux assemblys .NET et est utilisé par le chargeur d'assembly .NET pour connaître la version d'un assembly à charger / lier au moment de l'exécution.

Parmi ceux-ci, le seul qui est absolument requis par .NET est l' AssemblyVersionattribut. Malheureusement, il peut également causer le plus de problèmes lorsqu'il change sans distinction, surtout si vous nommez fortement vos assemblys.

Scott Dorman
la source
9

Pour garder cette question à jour, il convient de souligner qu'elle AssemblyInformationalVersionest utilisée par NuGet et reflète la version du package, y compris tout suffixe de pré-version.

Par exemple, une AssemblyVersion de 1.0.3. * Fournie avec le noyau asp.net dotnet-cli

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

Produit un package avec la version 1.0.3-ci-7 que vous pouvez inspecter avec réflexion en utilisant:

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

Il convient de noter quelques autres choses:

1) Comme indiqué dans la boîte de dialogue Propriétés de l'Explorateur Windows pour le fichier d'assemblage généré, il existe deux emplacements appelés "Version de fichier". Celui vu dans l'en-tête de la boîte de dialogue montre la AssemblyVersion, pas la AssemblyFileVersion.

Dans la section Informations sur les autres versions, il existe un autre élément appelé "Version du fichier". C'est là que vous pouvez voir ce qui a été entré comme AssemblyFileVersion.

2) AssemblyFileVersion est simplement du texte brut. Il n'a pas à se conformer aux restrictions du schéma de numérotation que AssemblyVersion fait (<build> <65K, par exemple). Il peut s'agir de 3.2. <Texte de la balise de sortie>. <datetime>, si vous le souhaitez. Votre système de construction devra remplir les jetons.

De plus, il n'est pas soumis au remplacement de caractères génériques qu'est AssemblyVersion. Si vous avez juste une valeur de "3.0.1. *" Dans AssemblyInfo.cs, c'est exactement ce qui s'affichera dans l'élément Autres informations sur la version -> Version du fichier.

3) Je ne connais pas l'impact sur un installateur d'utiliser autre chose que des numéros de version de fichiers numériques.

DavidM
la source
2

Lorsque AssemblyVersion d'un assembly est modifié, s'il a un nom fort, les assemblys de référence doivent être recompilés, sinon l'assembly ne se charge pas! S'il n'a pas de nom fort, s'il n'est pas explicitement ajouté au fichier de projet, il ne sera pas copié dans le répertoire de sortie lors de la génération, vous risquez donc de manquer les assemblys dépendants, en particulier après le nettoyage du répertoire de sortie.

linquize
la source
C'est très intéressant! Pourriez-vous développer un peu la partie "ne sera pas copié dans le répertoire de sortie"? Peut-être un lien vers où ce comportement est défini. Je n'ai jamais compris pourquoi certaines dépendances indirectes étaient copiées parfois, mais pas toujours. Cela doit être lié à 100%.
julealgon