Versionner Efficacement avec les Attributs AssemblyVersion et AssemblyFileVersion

This article is available in english.

On parle assez facilement des dernières technologies et des choses que l'on vient d'apprendre parce que c'est comme ca que les geeks fonctionnent, mais pour les nouveaux entrants, ce n'est pas toujours simple. C'est un débat assez large et récurrent, et pour ma part j'estime qu'il est bon de revenir de temps à autres sur les bonne pratiques pour ces nouveaux entrants.

Les attributs AssemblyVersion et AssemblyFileVersion

Lorsque l’on veut donner une version à une assembly .NET, deux moyens existent :

D’une manière générale, et par défaut dans les templates de Visual Studio 2008, on trouve le fichier AssemblyInfo.cs dans la section Properties d'un projet. Ce fichier ne va généralement contenir que l'attribut AssemblyVersion, ce qui va faire en sorte que la valeur par défaut de AssemblyFileVersion va être celle de AssemblyVersion. L'attribut AssemblyFileVersion est maintenant ajouté dans les templates de projets C# dans Visual Studio 2010, ce qui est une bonne chose.

Il est possible de voir la valeur de AssemblyFileVersion dans les propriétés de fichiers dans l'explorateur de fichiers de Windows, ou en ajoutant la colonne "File Version", toujours dans l'explorateur.

On va aussi trouver une numérotation automatique fournie par le compilateur, sous la forme de :

[assemblyAssemblyVersion("1.0.0.*")]

Chaque nouvelle compilation va donner une nouvelle version.

Cette notation peut convenir dans un premier temps, mais dès que l'on commence à avoir des projets un peu complexes, on va très rapidement introduire de l'intégration continue qui fournit des nightly builds. On va généralement vouloir donner une version à ses assemblies de manière à ce qu'il soit simple de retrouver la révision utilisée dans le système de sources pour compiler les assemblies.

On modifie alors les scripts de build dans Team Build de façon à utiliser des taches comme AssemblyInfo des MSBuild Tasks, et générer ainsi un nouveau fichier AssemblyInfo.cs qui contiendra la bonne version.


Publier un nouvelle version d'une assembly

Pour revenir sur l'utilité de versionner proprement une assembly, on veut généralement savoir assez rapidement, lorsque l'on a publié une build d'un projet, quelle est la version installée chez un client. Très souvent, on veut savoir la version publiée chez un client parce qu'il y a un problème, et qu'il faudra probablement fournir un correctif sous la forme d'une nouvelle assembly. Surtout si l'on ne peut pas réinstaller entièrement le logiciel chez le client.

Un Exemple plus ou moins réel

Prenons pour exemple que l'on dispose d'une solution avec deux assemblies signées avec un strong name, Assembly1 et Assembly2, avec Assembly1 qui utilise des types présents dans Assembly2, et qui enfin sont chacune versionnées avec AssemblyVersion avec la version 1.0.0.458. Ces assemblies font parties d'une build officielle publiée chez un client.

Si l'on veut fournir un correctif dans Assembly2, on va généralement créer une branche dans le système de gestion de sources pour la révision 458 soit 1.0.0.458, puis faire le correctif dans cette branche ce qui donnera la révision 460, soit 1.0.0.460.

Si l'on laisse le Système de build compiler cette nouvelle révision, on va avoir des assemblies qui comporteront la version 1.0.0.460. Si l'on prend juste assembly2 et que l'on place cela dans l'installation du client, le CLR ne chargera pas cette nouvelle version de l'assembly, car Assembly1 requiert d'avoir Assembly2 avec la version 1.0.0.458. On peut utiliser le paramètre bindingRedirect dans le fichier de configuration de l'application, mais cela n'est pas toujours pratique et si l'on modifie beaucoup d'assemblies, cela devient lourd à gérer.

On peut aussi compiler cette nouvelle version en changeant l'AssemblyVersion de 1.0.0.460 à 1.0.0.458 pour Assembly2, mais cela a le désavantage de faire en sorte que la version de cette assembly n'est plus vraiment la bonne, et cela complique énormément le diagnostic lors d'un éventuel problème suivant, pour savoir quelle version est effectivement installée.


Utiliser AssemblyFileVersion en plus

Pour éviter d'avoir ces problèmes de versions lors de la résolution des dépendances, il est possible de garder de garder constant le AssemblyVersion, et d'utiliser le AssemblyFileVersion pour donner la version effective de l'assembly.

La version présente dans le AssemblyFileVersion n'est pas utilisée par le Runtime .NET, mais est affichée dans les propriétés du fichier dans l'explorateur de Windows.

On va donc avoir dans le fichier AssemblyVersion la version originale de l'application, et placer la même version dans AssemblyFileVersion, puis on va changer le AssemblyFileVersion au fur et à mesure des différents correctifs publiés pour ces assemblies.

Microsoft utilise cette technique pour versionner les assemblies de .NET, puisque si l'on prend l'assembly System.dll pour .NET 2.0, on peut constater que le AssemblyVersion est 2.0.0.0, et que le AssemblyFileVersion est par exemple 2.0.50727.4927.


D'autres exemples de problèmes versions (Edit du 2010/07/11)

On peut trouver aussi certains autres cas de problèmes de chargement liés à la différence de version d'une assembly chargée par rapport à celle utilisée à la compilation.

Les Custom Behaviors de WCF

WCF donne la possibilité de fournir des custom behaviors pour altérer le comportement par défaut des bindings, et il est nécessaire de fournir le nom qualifié au complet et sans erreurs. C'est un bug assez ennuyeux dans WCF 3.x car il est assez complexe à débugger, et c'est un très bon exemple d'utilisation de nécessité de désactiver le "Just My Code" pour savoir pourquoi notre assembly ne se charge pas correctement.

Une bonne nouvelle cependant, ce bug très ancien a été corrigé dans WCF 4.0 !

Les Générateurs de Proxy Dynamiques

Certains générateurs de proxys dynamiques tels que Castle Dynamic Proxy 2 ou Spring.NET utilisent les types qualifiés à la source pour générer les proxy, et des problèmes de chargement peuvent se produire si l'assembly référencée par le proxy n'est pas exactement celle qui est chargée, avec ou sans Strong Name. Ces frameworks sont très utilisés lorsque l'on veut utiliser de l'AOP, ou bien dans des outils comme nHibernate, ActiveRecords ou iBatis.

Plus précisement, l'utilisation de la méthode ProxyGenerator.CreateInterfaceProxyWithTarget génère un proxy qui cible l'assembly contenant type référencé lors de la génération de l'interface proxisée.

Pour donner un exemple, prenons l'exemple d'une interface I1 dans une assembly A1(1.0.0.0), qui a une méthode qui utilise un type T1 dans une assembly A2(1.0.0.0). Si l'on change l'assembly A2 et que sa version devient A2(2.0.0.0), le proxy ne sera pas généré proprement puisque la référence T1/A2(1.0.0.0) sera utilisée puisque compilée dans A1(1.0.0.0), alors que l'on vient de charger la nouvelle version A2(2.0.0.0).

La bonne pratique de ne pas changer le AssemblyVersion permet de s'éviter des problèmes de ce genre. Ce n'est pas incontournable, mais c'est du travail en plus.

Et vous ?

Il ne s'agit bien sur que d'un exemple de "bonne pratique", qui fait semble avoir fait ses preuves.

Et vous, que faites-vous ? Quelles pratiques adoptez vous pour versionner vos assemblies ?


Publié samedi 10 juillet 2010 17:22 par jay
Classé sous ,
Ce post vous a plu ? Ajoutez le dans vos favoris pour ne pas perdre de temps à le retrouver le jour où vous en aurez besoin :

Commentaires

# re: Versionner Efficacement avec les Attributs AssemblyVersion et AssemblyFileVersion @ dimanche 11 juillet 2010 22:22

Hum, les assemblys ne requierent d'avoir la même version que si elles sont signées ou bien placées dans le GAC, non ?

Dans le cadre d'un projet "réel" ou les différentes assemblys sont juste posées ensemble dans le répertoire d'application, n'importe quelle version présente sera chargée.

Jem

# re: Versionner Efficacement avec les Attributs AssemblyVersion et AssemblyFileVersion @ lundi 12 juillet 2010 04:09

En effet, plus précisement si elles sont signées, le CLR ne les chargera pas. Je vais clarifier cela :)

Dans les autres exemples de chargement qui peuvent poser problème, on va trouver les frameworks du type Castle avec son DynamicProxy2 qui génèrent du code en utilisant le nom qualifié du type référencé. Changer la version de l'assembly pose des problèmes lors de la génération du proxy.

Un autre exemple est la fourniture de behaviors dans WCF, ou le nom qualifié au  complet doit être présent, cela oblige à changer la version à cet endroit aussi. (A cause d'un bug... http://connect.microsoft.com/wcf/feedback/details/216431/wcf-fails-to-find-custom-behaviorextensionelement-if-type-attribute-doesnt-match-exactly).

jay

# re: Versionner Efficacement avec les Attributs AssemblyVersion et AssemblyFileVersion @ lundi 12 juillet 2010 04:46

Voila, j'ai ajouté un peu plus de détails.

Merci Jem pour la relecture :)

jay


Les 10 derniers blogs postés

- Merci par Blog de Jérémy Jeanson le 10-01-2019, 20:47

- Office 365: Script PowerShell pour auditer l’usage des Office Groups de votre tenant par Blog Technique de Romelard Fabrice le 04-26-2019, 11:02

- Office 365: Script PowerShell pour auditer l’usage de Microsoft Teams de votre tenant par Blog Technique de Romelard Fabrice le 04-26-2019, 10:39

- Office 365: Script PowerShell pour auditer l’usage de OneDrive for Business de votre tenant par Blog Technique de Romelard Fabrice le 04-25-2019, 15:13

- Office 365: Script PowerShell pour auditer l’usage de SharePoint Online de votre tenant par Blog Technique de Romelard Fabrice le 02-27-2019, 13:39

- Office 365: Script PowerShell pour auditer l’usage d’Exchange Online de votre tenant par Blog Technique de Romelard Fabrice le 02-25-2019, 15:07

- Office 365: Script PowerShell pour auditer le contenu de son Office 365 Stream Portal par Blog Technique de Romelard Fabrice le 02-21-2019, 17:56

- Office 365: Script PowerShell pour auditer le contenu de son Office 365 Video Portal par Blog Technique de Romelard Fabrice le 02-18-2019, 18:56

- Office 365: Script PowerShell pour extraire les Audit Log basés sur des filtres fournis par Blog Technique de Romelard Fabrice le 01-28-2019, 16:13

- SharePoint Online: Script PowerShell pour désactiver l’Option IRM des sites SPO non autorisés par Blog Technique de Romelard Fabrice le 12-14-2018, 13:01