Comment fonctionne exactement la propriété «Version spécifique» d'une référence d'assembly dans Visual Studio?

156

Aujourd'hui, j'ai examiné de plus près la propriété "Version spécifique" des références d'assembly dans Visual Studio 2010. Après quelques expériences avec des résultats inattendus, j'ai décidé d'en apprendre le plus possible sur le fonctionnement de la propriété. Même SO, il me semble, n'a pas toutes les réponses, alors voici ma tentative d'auto-réponse à la question:

Comment fonctionne exactement la propriété «Version spécifique» d'une référence d'assembly dans Visual Studio?

herzbube
la source

Réponses:

255

C'est une propriété au moment de la compilation!

L'une des choses les plus importantes à savoir est que "Version spécifique" est une propriété qui prend effet au moment de la compilation et non au moment de l'exécution.

C'est à propos de quoi?

Lorsqu'un projet est généré, les références d'assembly du projet doivent être résolues afin de trouver les assemblys physiques que le système de génération doit utiliser. Si le contrôle "Version spécifique" est effectué (voir section "Quand" Version spécifique "est-il coché?"), Cela affecte le résultat du processus de résolution d'assemblage:

  • Le système de génération localise un assembly physique qu'il peut potentiellement utiliser
  • Le système de génération compare la version de l'assembly physique à la version de l'assembly stockée dans le fichier .csproj pour la référence d'assembly
  • Si les deux versions d'assembly sont exactement les mêmes, le processus de résolution réussit et l'assembly physique trouvé est utilisé pour la génération
  • Si les deux versions d'assemblage ne correspondent pas, l'assemblage physique est rejeté et le processus de résolution se poursuit en localisant l'assemblage potentiel suivant
  • Si aucun autre assemblage physique potentiel ne peut être localisé, le processus de résolution échoue. Cela entraîne un avertissement du compilateur (avertissement MSB3245) qui vous indique que la référence n'a pas pu être résolue.
  • Chose intéressante, la construction continue alors! Si le code n'a aucune référence réelle à l'assembly, la génération réussit (avec l'avertissement mentionné précédemment). Si le code a des références, la génération échoue avec une erreur qui ressemble à si le code utilisait des types ou des espaces de noms inconnus. La seule indication pour laquelle la compilation a vraiment échoué est l'avertissement MSB3245.

Ordre dans lequel les assemblages sont résolus

L'ordre dans lequel le processus de résolution d'assembly localise les assemblys potentiels semble être le suivant:

  1. L'assembly référencé par l' <HintPath>élément dans le fichier .csproj
  2. Le chemin de sortie du projet
  3. Le GAC

Notez que si plusieurs versions de l'assembly existent dans le GAC, le processus de résolution tente d'abord de résoudre l'assembly avec la version la plus élevée. Ceci n'est important que si le contrôle "Version spécifique" n'est pas effectué.

Quand la "Version spécifique" est-elle cochée?

Visual Studio fonde sa décision d’effectuer la vérification de «version spécifique» sur deux informations contenues dans le fichier .csproj:

  • La présence ou l'absence de l' <SpecificVersion>élément, et sa valeur (s'il est présent)
  • La présence ou l'absence d'informations de version dans la référence d'assemblage

Voici à quoi ressemble une référence d'assembly typique avec des informations de version:

<Reference Include="Foo, Version=1.2.3.4, Culture=neutral, processorArchitecture=MSIL">
  <SpecificVersion>True</SpecificVersion>
  <HintPath>..\..\Bar\Foo.dll</HintPath>
</Reference>

Et voici à quoi ressemble la référence d'assembly sans informations de version:

<Reference Include="Foo">
[...]

Le tableau suivant montre quand la vérification «Version spécifique» est effectuée et quand elle ne l'est pas.

                            |     Version information
                            |  Present       Not present
----------------------------+------------------------------
<SpecificVersion>           |
- Present, has value True   |    Yes (1)        Yes (check always fails) (2)
- Present, has value False  |    No  (3)        No (4)
- Not present               |    Yes (5)        No (6)

La chose surprenante ici est qu'aucune vérification n'est effectuée si les deux <SpecificVersion>et les informations de version sont absents (cas 6). Je me serais attendu à ce que la vérification soit effectuée et qu'elle échoue toujours (comme dans le cas 2) car, à ma connaissance, l'absence de <SpecificVersion>implique la valeur par défaut "True". Cela peut être une bizarrerie de Visual Studio 2010 où j'ai fait mes tests.

Lorsque vous examinez les propriétés d'une référence d'assembly dans l'interface utilisateur de Visual Studio (sélectionnez la référence et appuyez sur F4), la valeur que vous voyez pour la propriété «Version spécifique» vous indique si Visual Studio va effectuer ou non la «Version spécifique» vérifier. Dans le cas 6, l'interface utilisateur affichera "True", bien que l' <SpecificVersion>élément ne soit pas présent dans le fichier .csproj.

Effets secondaires sur "Copier local"

Si la propriété «Copier local» est définie sur «True» mais que le processus de résolution d'assembly échoue en raison de la vérification «Version spécifique», aucun assembly n'est copié.

Matériel de référence

herzbube
la source
Merci pour le détail. Puis-je simplement vérifier ... la vérification de la version d'assembly se produit uniquement pour les assemblys avec des noms forts; Est-ce correct? De plus, lorsque nous parlons de vérifier la version d'un assembly, cela se fait-il en comparant le nom de l'assembly référencé ? (Dans le cas d'un assembly avec un nom fort, ce nom inclut les informations de version, donc ce n'est pas comme si un champ de version séparé était vérifié?)
Gavin Hope
2
@GavinHope Question 1: Non, la vérification de version ne se limite pas aux noms forts, principalement parce qu'un nom d'assemblage peut inclure la version mais toujours pas être un nom fort (par exemple s'il manque la PublicKeyToken=pièce). De plus, si vous vérifiez le tableau vers la fin de mon message, vous pouvez voir que la vérification de version peut se produire même si la Version=pièce est absente du nom de l'assemblage dans le .csproj. Question 2: Je suppose que le nom de l'assembly est utilisé pour la comparaison, oui. Je ne connais aucune autre source d'information.
herzbube
"Dans le cas 6, l'interface utilisateur affichera" True ", bien que l'élément <SpecificVersion> ne soit pas présent dans le fichier .csproj." - Il semble que la valeur par défaut est True . Après avoir basculé la version spécifique dans l'interface utilisateur sur True, la <SpecificVersion>balise a été complètement omise, qui avait auparavant la valeur False .
samis
@herzbube - Je pense que la signification de "Version spécifique" dans la fenêtre Visual Studio> Propriétés du projet est le contraire de ce que vous dites ici (ce qui est le contraire de ce à quoi vous vous attendez). Visual Studio indique que la valeur (true ou false) de "Specific Version" "indique si cet assembly peut être résolu sans tenir compte des règles de multi-ciblage pour la résolution d'assembly".
N73k
35

Lorsque vous ajoutez une référence, Visual Studio enregistre la [AssemblyVersion] de l'assembly dans le fichier projet. C'est important. Si, par exemple, vous créez un correctif de bogue un an plus tard, vous voulez vous assurer que vous reconstruisez le projet avec exactement la même version de la référence afin que ce soit un véritable drop-in. Vous obtiendrez une erreur si l'assemblage de référence a changé.

Mais ce n'est pas toujours souhaitable. Certains programmeurs laissent la version de l'assembly s'incrémenter automatiquement, générant une nouvelle version à chaque reconstruction. Même si l'interface publique de l'assembly n'a jamais changé. Certains configurent leur projet en utilisant Nuget pour obtenir des bibliothèques et le laissent mettre à jour automatiquement la bibliothèque lorsqu'une nouvelle version est disponible. Ils aimeront définir la propriété Specific Version sur False pour supprimer l'erreur de compilation.

Il est assez important de comprendre la conséquence, vous devez redéployer la version complète du programme pour éviter les accidents. Les non-concordances de version à l'exécution bloquent le programme et ne peuvent être supprimées qu'avec un <bindingRedirect>dans le fichier .config, ce qui est risqué.

Hans Passant
la source
2
Merci pour l'info pourquoi la "version spécifique" est importante, c'est un bon compagnon pour les aspects purement mécaniques que je couvre dans ma réponse.
herzbube
@Hans Passant - votre dernier paragraphe est-il valide pour SpecificVersion True ou False? Je pense que ce sont les conséquences lorsque vous le définissez sur vrai.
GreenEyedAndy
1
SpecificVersion s'applique uniquement à la création de votre application. Lors de l'exécution, le CLR insiste toujours sur une correspondance exacte avec le numéro de version de l'assemblage de référence. Si vous avez utilisé une version plus récente au moment de la construction, il doit également s'agir de cette version plus récente au moment de l'exécution.
Hans Passant
1
Méfiez-vous de VS2013 et .Net 4.5.1 AutoGenerateBindingRedirects Ils peuvent rediriger la liaison dll vers une version plus récente même si vous lui avez dit d'utiliser une version spécifique
Dennis Kuypers
1
@HansPassant Je pensais que le CLR ne prend pas en compte les [AssemblyVersion]assemblys qui ne sont pas signés par un nom fort.
tm1