Log4Net – Multi configuration

Pour avoir une configuration de Log4net propre à chaque configuration de votre solution, vous pouvez utiliser les XDT transformations , une implémentation automatisée est fourni par l’extension SlowCheetah avec interface graphique pour Visual Studio.
Une fois cette extension installée, clic-droit sur le fichier log4net.config et sélectionner « Add Transform ».

2 sous-fichiers sont ajoutés:

log4net.config
|
+—- log4net.Debug.config
+—- log4net.Release.config

La transformation la plus simple, « Replace », est faîte en ajoutant le tag xml xdt:Transform= »Replace » sur le noeud que vous souhaîtez remplacer.

exemple:

<log4net xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform" xdt:Transform="Replace">

Remplacera le noeud log4net complet.

Un exemple de résultat log4net est ci-inclus .
log4net.config
log4net.Debug.config
log4net.Release.config

Vous pouvez pré visualiser la transformation en effectuant un clic droit sur la version debug ou release et en sélectionnant « Preview Transform » .

La syntaxe de transformation est définie dans la documentation disponible sur:

MSDN Doc Xdt transform

Nuget – Bonnes Pratiques

Pourquoi choisir Nuget ?

Prenons une situation classique d’un développement en entreprise…

Contexte:

  • Nombreux projets
  • nombreuses libs communes interdépendantes
  • peu ou pas de stockage partagé ou mal utilisé
  • Svn ou Git

Sans Nuget

  • bibliothèques communes éparpillées sur chaque poste en différentes versions
  • plusieurs répertoires de bibliothèques communes avec leurs dépendances mélangées et incomplètes, avec pour seuls critères le nom du fichier dll et son numéro dans les propriétés du fichier.
  • Chaque développeur va compiler ces bibliothèques sans formalisme particulier à partir du gestionnaire de source, impossible de savoir quel version est réellement utilisée dans le projet, la version a-t’elle bien été incrémentée? …etc.
  • une bibliothèque X dépend de A en version 1.0 seulement, une bibliothèque Y dépend de A en version 2 ou +, le développeur ne sera pas averti du problème, et perdra du temps à comprendre son problème.
  • une bibliothèque X dépend de A en version 1.0 ou +, une bibliothèque Y dépend de A en version 2 ou +, X est installé en premier avec A1.0, Y ensuite, le développeur devra penser à upgrader A, fait non évident.

Résultats

  • Partage entre équipes très compliqué et non interactif
  • difficulté d’installer une lib en version précise et ces dépendances
  • Difficulté de monter en version sur une lib, car impossible de connaître rapidement toute les ramifications
  • Option viable pour un petit projet d’entreprise (un seul produit, très peu de lib, 2-3 développeurs max), mais pas industrialisable sur X projets et X bibliothèques. contre-productif…

Avec Nuget:

  • bibliothèque formalisée dans un paquet avec une version précise
  • paquet centralisé dans un serveur ou espace partagé
  • les dépendances entre lib sont définies au niveau du paquet, l’outil Nuget permet de rapatrier l’ensemble des dépendances d’une lib dans une version compatible.
  • lisibilité du nom de la lib, de la version, de ces dépendances, de son origine, de sa licence, …etc, directement dans Visual Studio.
  • la montée de version des bibliothèques d’une solution est automatisée avec une fonction d’update de Nuget.
  • une bibliothèque X dépend de A en version 1.0 seulement, une bibliothèque Y dépend de A en version 2 ou +, le développeur sera averti du problème.
  • une bibliothèque X dépend de A en version 1.0 ou +, une bibliothèque Y dépend de A en version 2 ou +, X est installé en premier avec A1.0, Y ensuite, Nuget met à jour automatiquement A.
  • partage entre équipes simplifié et synchronisé, toujours accès aux dernières versions sans interventions extérieures.

Relation Nuget / SCM / restauration automatique

Une source de problèmes liés à Nuget est les restaurations des dépendances.
2 politiques s’opposent, l’une consiste à commiter toutes bibliothèques au prix d’une charge de stockage plus grande sur le SCM (git / svn / …) l’autre à restaurer dynamiquement au risque de ne plus retrouver de vieilles version de dépendance aujourd’hui supprimée.
Ce choix dépend de votre infrastructure et de la durée de vie de votre projet…

Pour plus d’informations :

Une description plus complète de cette problématique est faite sur l’article suivant :
http://blog.ploeh.dk/2014/01/29/nuget-package-restore-considered-harmful/

Documentation officiel
http://docs.nuget.org/docs/workflows/migrating-to-automatic-package-restore

Blog d’un mainteneur du projet Nuget :
http://blog.davidebbo.com/2014/01/the-right-way-to-restore-nuget-packages.html

Versionnement des bibliothèques

Nuget se base sur la version de votre paquet pour résoudre les dépendances. L’algorithme de résolution utilise la nomenclature SemVer, un standard en numérotation de version.
Si vous ne respectez pas cette nomenclature, la résolution sera faussée et ça sera l’enfer sur votre solution !

Semantic Versioning (SemVer) en bref

SemVer décrit, pour les auteurs, une manière de définir des versions sémantiquement cohérentes. En un mot, les versions sémantiques ressemblent à MAJEURE.MINEURE.CORRECTIF(optionel=+metaData)), tels que:

  • le numéro de version MAJEUR quand il y a des changements rétro-incompatibles,
  • le numéro de version MINEUR quand il y a des changements rétro-compatibles,
  • le numéro de version de CORRECTIF quand il y a des corrections d’anomalies rétro-compatibles

Optionnellement un numéro de build ou de révision peut être ajouté en méta-données comme par exemple 1.0.0-beta+exp.sha.5114f85. Cette extension est ignoré pour le calcul des releases mais pris en compte avec l’argument « -Pre ».
Règle de dépendances entre paquet

Algorithm de résolution

  • 1.0 = 1.0 ≤ x
  • (,1.0] = x ≤ 1.0
  • (,1.0) = x < 1.0
  • [1.0] = x == 1.0
  • (1.0) = invalide
  • (1.0,) = 1.0 < x
  • (1.0,2.0) = 1.0 < x < 2.0
  • [1.0,2.0] = 1.0 ≤ x ≤ 2.0
  • vide = dernière version.

Avoir une règle de versionnement n’est que la moitié du puzzle. L’autre moitié est d’être en mesure de choisir la meilleure version parmi tous les candidats qui sont disponibles.
Un scénario:

  • A dépend de X 1.1 (qui signifie « >= 1.1 » comme indiqué ci-dessus)
  • B dépend de X 1.2
  • C dépend de X 2.0.1
  • X a des versions 1.0, 1.1, 1.2, 2.0 , 2.0.1+alpha, 2.0.1, 3.0, 3.0.1, 3.0.2+beta et 4.0 disponible.

La résolution de la version utilisée par NuGet est de toujours choisir la version la plus basse d’une dépendance.

Voyons donc ce qui se passera dans les différents scénarios :

  • Si vous venez d’installer A, vous aurez X 1.1
  • Si vous installez juste B, vous aurez X 1.2
  • Si vous venez d’installer C, vous aurez X 2.0.1

Si vous installez d’abord A, puis B , puis C

  • Vous obtenez d’abord X 1.1 lorsque vous installez A
  • X sera mis à jour en 1.2 lorsque vous installez B
  • X sera mis à jour en 2.0.1 lorsque vous installez C

Remarque : X.Y.Z+meta sera toujours inférieur à X.Y.Z et sera pris en compte qu’avec l’option « Prerelease ».

Mise à jour de dépendance après installation de paquet

Avant NuGet 2.5, quand un paquet à installé dépend d’un paquet déjà installé dans le projet, la dépendance sera mis à jour dans le cadre de la nouvelle installation, même si la version existante satisfait la dépendance. Cette mise à jour se limitera aux versions rétro compatibles.

À partir de NuGet 2.5, si une version de la dépendance est déjà satisfaite, la dépendance ne sera pas mis à jour lors d’autres installations de paquets.

Le scénario :

Le référentiel source contient le paquet B avec la version 1.0.0 et 1.0.2 . Il contient également un paquet qui a une dépendance sur B ( > = 1.0.0 ).
Supposons que le projet actuel a déjà la version du paquet B 1.0.0 installé . Maintenant, vous voulez installer le paquet A.

En NuGet 2.2 et plus:
Lors de l’installation du paquet A, NuGet mettra à mise à jour automatique B à 1.0.2, même si la version existante 1.0.0 satisfait déjà la contrainte de dépendance qui est > = 1.0.0.

En NuGet 2.5 et plus récent:
NuGet ne mettra plus mettre à jour B, car il détecte que la version existante 1.0.0 satisfait la contrainte de dépendance de version.
Pour plus de détails :

Documentation officiel
http://blog.davidebbo.com/2011/01/nuget-versioning-part-2-core-algorithm.html

Génération de paquet

Génération initiale du descriptif

Pour créer un descriptif de paquet, utilisez la commande ci-dessous à la racine de votre solution :

$> Nuget spec

Compléter ce fichier avec l’information dont vous disposez (licence, description,…). Vous pouvez laisser les token $xxx$ intact, ils seront rempli automatiquement par les informations de AssemblyInfo.cs

Générer le paquet

Remplissez le fichier AssemblyInfo.cs comme vous le feriez pour produire votre release.

Compilez en release ou exécutez la commande suivante :

$> msbuild votre-projet-ou-solution /target:Rebuild /property:Configuration=Release

Créez le paquet avec ces symbols de débogage :

$> nuget pack votre-projet-ou-solution -Symbols -Prop Configuration=Release

Uploader sur le serveur Nuget les 2 fichiers générés en même temps, le xxxx.nupkg et le xxxx.symbols.nupkg.

Bibliothèques interdépendantes

Ajouter le flag –IncludeReferencedProjects si votre projet a pour dépendance d’autre projet locaux à la solution qui vont être également converti en paquet Nuget.

Débugger avec les paquets Nuget

Le paquet symbols.nupkg contient les symboles et le code source de votre paquet, il vous permet de débugger votre application en ayant accès au code de ces dépendances.

Ces symboles sont stockés sur le serveur Nuget de symbole.

Pour configurer Visual Studio afin qu’il utilise ces symboles, suivez le tutorial en lien

INotifyPropertyChanged et PostSharp en AOP