| Prise en main du Framework Enterprise Library (2ème Partie : Configuration Application Block) | ||
Auteur : Laurent Desmons
Cet article est le 2ème d'une série de huit articles consacrés à la prise en main du Framework Enterprise Library. Le sommaire de cette série ainsi que le 1er article peuvent se trouver ici : Prise en main du Framework Enterprise Library (1ère Partie).
Cette 2ème partie entre dans le coeur du sujet en disséquant les principes, l'exploitation et le fonctionnement avancé d'un block indispensable : le Configuration Application Block. Ce block est indispensable pour au moins 2 raisons:
Une compréhension complète des mécanismes sous-jacents à ce block constitue donc un préambule indispensable à la maîtrise et à l'exploitation poussée de l'ensemble des EntLib.
Le sommaire de cet article est ainsi le suivant :
Passons donc tout de suite à la présentation de ce block.
Le Configuration Application Block a pour objectifs de :
Il est conçu de façon à être autonome et homogène par rapport aux autres blocks. Sa mise en oeuvre reprend des principes qu'on retrouve à l'identique pour l'ensemble des EntLib.
La mise en oeuvre du Configuration Application Block est très simple, car il suffit de suivre la démarche suivante :
1 - Définition de la structure des données de configuration
2 - Déclaration d'une section de configuration
3 - Ecriture de la configuration
4 - Lecture de la configuration
Les étapes 1 et 2 sont à faire une fois (plus exactement : à chaque fois que la configuration doit être modifiée). Les étapes 3 et 4 peuvent naturellement être effectuées plusieurs fois. Afin de suivre ces étapes dans le détail, je vais me fonder sur l'IHM de tests livrée avec cet article : EntLibConfig. Il s'agit d'un exemple WinForm tout simple qui permet d'écrire et de lire une structure de données de configuration, ici en l'occurence les paramètres qui permettent d'identifier un magasin parmi toute une chaîne :

On saisit les données du magasin puis on appuye sur "Ecrire" pour écrire les données dans la configuration. Ensuite un appui sur "Lire" permet d'afficher les données saisies précédemment en lisant depuis la configuration. Les données sont volontairement de types différents (on est complètement libre de leurs structures).
Suivons donc les étapes en détail pour en arriver à ce simple résultat.
La première chose à faire est bien évidemment de définir la structure des données de configuration, autrement dit la classe qui représente les données à configurer. Dans un projet réel on fera en sorte de maintenir cette classe proprement (dans une assembly séparée et partagée par exemple) mais pour l'instant cette classe est définie dans le code source de notre application, dans le fichier ConfigMagasin.cs exactement:

Maintenant que la structure des données de configuration est connue de l'application, il faut déclarer une section dans le fichier de configuration de l'application, afin que le Configuration Application Block puisse retrouver les informations de configuration propres à l'application. Le principe a déjà été exposé dans le 1er article de cette série : on utilise pour cela l'outil de configuration livré avec les EntLib, de façon à modifier le fichier app.config pour y créer une section de configuration qui contient les informations nécessaires pour faire le lien avec l'endroit et le format où sont stockées les données; nous verrons un peu plus loin en effet que les données ne sont pas stockées dans le fichier de configuration lui-même, et qu'il est possible de choisir :
Ici, j'ai choisi de stocker les informations de configuration dans un fichier (File Storage Provider) au format XML (XML Serializer Transformer). Pour cela il suffit de procéder de façon hiérarchique :
Et voilà! Cela parait long mais c'est fait en quatre clicks de souris, et on obtient alors le résultat suivant :

Il faut comprendre que ces manipulations ont uniquement pour effet de modifier le fichier app.config pour y faire apparaître ce qu'on vient de faire. L'utilisation de l'outil des EntLib n'est donc pas du tout nécessaire mais vous conviendrez sans peine qu'il est quand même bien plus pratique que de modifier le fichier app.config à la main ! Ce fonctionnement se retrouve dans tous les blocks des EntLib.

Les lecteurs attentifs du 1er article se rappelleront sans doute ici qu'il est nécessaire (sous peine d'erreurs en debug par exemple) que le fichier configmagasindata.config ainsi spécifié soit dans le même répertoire que le fichier app.config, et donc au même niveau que l'exécutable lui-même; or ce n'est pas le cas par défaut (Visual Studio .NET ne copie que le fichier app.config dans le répertoire bin, rien d'autre). Il faut donc ajouter un événement de génération post-build qui consiste à copier ce fichier de configuration (ainsi que tous les autres éventuellement) dans le répertoire d'exécution du projet :
copy $(ProjectDir)\configmagasindata.config $(TargetDir)
Tout est configuré maintenant. Il ne nous reste plus qu'à écrire dans le fichier configmagasindata.config (puisque nous avons choisi un fichier comme support de stockage). On retrouve ici la notion d'Abstract Factory qui est omni-présente dans les EntLib (et apporte une un réel gain de simplicité, homogénéité et évolutivité à ce framework); pour ce block cette factory se nomme ConfigurationManager et permet de lire et d'écrire dans n'importe quelle section de configuration de l'application.
Effectuons donc maintenant l'écriture de nos données de configuration. Bien entendu, au préalable il faut :

![]()
Ensuite, pour écrire nos données il faut simplement appeler la méthode statique WriteConfiguration() de la classe ConfigManager, en fournissant le nom de la section de configuration créée auparavant ("ConfigMagasin") et l'objet à écrire. Voici par exemple le code de l'événement Click du bouton btnEcrire de notre IHM de tests, qui construit un objet ConfigMagasin avec les données saisies et écrit le contenu de cet objet dans le fichier de données de configuration :

Et voilà, une ligne suffit ! Pour se convaincre du résultat il suffit d'ouvrir le fichier configmagasindata.config qui contient les données écrites au format XML:

Il faut remarquer ici tout de suite que le code client ne manipule que des objets, pas des fichiers ou du XML : les informations de stockage (type, emplacement, format...) ne sont spécifiées nulle part dans le code source écrit car il s'agit d'une configuration prise intégralement en charge par le Configuration Application Block. La modification du format de stockage n'implique aucune modification du code source, ce qui est un point très important pour la maintenance et l'évolutivité d'une application (sans compter les notions de sécurité).
Lire les données de configuration est aussi simple que de les écrire, et consiste à appeler la méthode statique GetConfiguration() de la classe ConfigurationManager, en spécifiant le nom de la section de configuration désirée ("ConfigMagasin") et en castant le résultat obtenu vers le type des données considérées, ici la classe ConfigMagasin. Voici par exemple le code de l'événement Click du bouton btnLire de notre IHM de tests, qui récupère un objet ConfigMagasin avec les données écrites dans le fichier de données de configuration et affiche les propriétés de cet objet à l'écran:

Voilà, c'est à peu près tout ce qu'il y a à savoir sur ce block pour l'utiliser au quotidien !
Je vous propose maintenant de dévoiler un peu son fonctionnement, et de revenir notamment sur les notions de Storage Provider et de Serializer Transformer, afin de vous permettre d'implémenter vos propres moyens de stockage personnalisés (comme une base de données par exemple).
Rappelons que le code client utilise systématiquement la classe ConfigurationManager et ses méthodes WriteConfiguration() et GetConfiguration().
L'architecture du Configuration Application Block repose sur le schéma suivant, tiré de la documentation MSDN du block :

Ce schéma montre bien les principaux composants du block:
Détaillons maintenant ces composants (je m'inspire ici largement de la présentation MSDN).
Le Configuration Application block différencie deux fichiers de configuration séparés :
La classe ConfigurationManager est le point d'entrée unique (façade statique) pour lire et écrire des données de configuration dans une section spécifique et à un emplacement donné. Il utilise le fichier de configuration de l'application.
En interne, les méthodes statiques de cette classe utilisent une instance de la classe ConfigurationBuilder, responsable de la création des objets Storage Provider et des Transformers.
Le schéma suivant, tiré du site de Ron Jacobs, montre bien le découplage qui existe entre l'application et le stockage de la configuration : le Storage Provider est le composant obligatoire qui permet d'accéder physiquement au stockage des informations (fichier, base de données, registry...), tandis que le Transformer est le composant qui permet de spécifier le format de stockage de ces données. Le Transformer est un composant optionnel car chaque Storage Provider fournit un format de stockage par défaut.

Un Storage Provider est une classe qui implémente l'interface IStorageProviderWriter, utilisée pour écrire des données de configuration. Cette interface dérive de l'interface IStorageProviderReader, utilisée pour lire les données de configuration.
Voici la définition de l'interface IStorageProviderReader:

Et voici la définition de l'interface IStorageProviderWriter:

Le Configuration Application Block fournit un provider qui supporte cette interface, le XmlFileStorageProvider, qui lit et écrit des données dans un fichier XML. Une classe intermédiaire, StorageProvider, permet de faciliter la conception de StorageProvider personnalisés (en dérivant simplement de StorageProvider, et en implémentant IStorageProviderWriter s'il faut écrire).
Un Transformer est une classe qui implémente l'interface ITransformer, utilisée pour transformer des données de configuration entre le format utilisé par l'application et le format utilisé par le Storage Provider.
Voici la définition de cette interface :

Le Configuration Application Block founit un transformer qui supporte cette interface, le XmlSerializerTransformer, qui sérialise/désérialise des XmlNode de façon par exemple à ce que le XmlfileStorageProvider puisse stocker n'importe quelle structure de données au format XML.
Une classe intermédiaire, TransformerProvider, permet de faciliter la conception de Transformer personnalisés (en dérivant simplement de TransformerProvider).
Pour des raisons de performance, chaque section de configuration est mise en cache sous forme de hashtable. Quand un client demande des données de configuration, la classe ConfigurationBuilder recherche les données dans le cache, et les renvoie alors sans accéder au stockage physique. L'objet ConfigurationBuilder efface le cache sur détection d'une modification de la configuration.
Après ce rapide tour d'horizon de l'architecture du Configuration Application Block, je vais maintenant aborder des notions avancées, en commençant par la protection des données par cryptage.
Par défaut les informations de configuration sont stockées en clair. Il est possible de protéger les informations sensibles en les cryptant. L'ensemble des sections d'un bloc de configuration sont cryptées en utilisant le même algorithme. Pour crypter certaines informations :
Le choix d'un algorithme de cryptage se fait dans le fichier de configuration de l'application, et le plus simple est encore d'utiliser l'IHM de configuration et de sélectionner l'algorithme dans le noeud "Encryption Settings". Les Entlib sont livrées par défaut avec système de cryptage basé sur le stockage d'une paire de clés privées/publiques stockées en clair dans un fichier texte ("'File Key Algorithm Storage Provider") :

Il faut ensuite spécifier si on veut créer une nouvelle paire de clés ou utiliser des clés existantes. C'est bien pratique par exemple pour partager les protections entre différents projets et centraliser la sécurité:

Puis il faut choisir un algorithme de cryptage parmi une liste qui reprend les algorithmes les plus répandus (on peut même à ce stade charger un nouvel algorithme depuis une DLL) :

Enfin il faut soit spécifier la valeur d'une clé soit laisser l'outil en générer une automatiquement :

Les clés étant stockées en clair dans un fichier texte, il faut bien se rendre compte alors que n'importe qui peut avoir accès à ce fichier de clés et s'en servir pour décrypter les informations de configuration. L'outil propose alors de crypter ces fichiers de clés en utilisant la Data Protection API (ou DPAPI) intégrée au système d'exploitation Windows. Cette API est utile quand les ACLs ne suffisent plus. Les DPAPI fonctionnent selon 2 modes : le mode "user" et le mode "machine" :
en mode "user" la possibilité de décrypter le fichier est réservée uniquement à l'utilisateur (login) ayant crypté le fichier
en mode "machine" restreint le décryptage à la machine utilisée pour crypter le fichier. Pour restreindre encore plus l'accès en mode machine (puisque n'importe quel utilisateur ayant ouvert une session sur cette machine peut alors décrypter le fichier), le Configuration Application Block requiert en plus de fournir un password (appelé Entropy Key)
L'utilisation de la DPAPI est facultative, notamment si le fichier de clés est protégé par un autre moyen. L'outil de configuration permet de spécifier le nom du fichier de clés utilisé, ainsi que l'utilisation (ou non) de la DPAPI et, donc, du mode et de l'entropy key si mode machine :

Après sélection du fichier on a terminé la configuration de la sécurité à appliquer à notre section de configuration :

Il ne reste plus maintenant qu'à spécifier quelles données sont à sécuriser.
Il est très simple de crypter une donnée de configuration : il suffit simplement de donner la valeur "true" à la propriétés "Encrypt" de chaque structure de configuration, par exemple ici "ConfigMachine" (si on veut plus de finesse, il faut multiplier les structures de configuration):

Le Configuration Application Block propose un mécanisme d'avertissement de la modification de la configuration actuelle; toutefois cette notification est dépendante du Storage Provider et tous n'offrent pas cette possibilité. Le XmlFileStorageProvider supporte cette notification, et sa mise en oeuvre est des plus simples : il suffit juste de s'abonner à l'event ConfigurationManager.ConfigurationChanged en fournissant un handler qui sera appelé à chaque modification de la configuration; par exemple ici dans notre IHM de tests, le code suivant permet d'afficher une messagebox d'avertissement à chaque fois que le fichier de configuration est modifié : (le paramètre ConfigurationChangedEventArgs

Le site des Release de la communauté GotDotNet des EntLib fournit un patch (N°1473) qui apporte de nouveaux providers bien pratiques, notamment:
Ce patch nécessite une recompilation complète des sources ainsi que de
redérouler les .BAT d'installation (de plus, pour être sûr, il faut réappliquer
le patch N°1475 évoqué dans le 1er article de cette série). Les DLL résultantes
(EnterpriseLibrary.Extensions.dll and
EnterpriseLibrary.Extensions.Configuration.Design.dll) doivent être copiées
ensuite dans le répertoire "bin" des EntLibs pour être prises en compte.
Ensuite les nouveaux providers sont alors disponibles dans l'outil de configuration des EntLib comme n'importe quel autre provider :

L'intérêt ici est de bien sûr de pouvoir donner les propriétés du provider dans cet outil, par exemple, pour SqlServer, la chaîne de connexion (éventuellement cryptée!), ou bien le nom des procédures stockées que le SqlStorageProvider doit utiliser pour lire ou écrire la configuration :

Cet article vous a présenté les principes, la mise en oeuvre et le fonctionnement interne et avancé du Configuration Application Block. Ce block est simple d'utilisation, mais suffisamment puissant et customisable pour répondre à tous les besoins de configuration. Il est recommandé de bien en maîtriser le contenu avant de passer à la suite de l'étude du Framework Enterprise Library.
Le prochain article de cette série sera consacré à un autre block fondamental : le Logging and Instrumentation Application Block.
Auteur : Laurent Desmons
Copyright © Mai 2005
Ressources
Le Configuration Application Block sur MSDN : http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnpag2/html/config.asp
Le site (indispensable!) de Ron Jacobs : http://www.ronjacobs.com
Les Release de la communauté GotDotNet des EntLib : http://www.gotdotnet.com/workspaces/releases/viewuploads.aspx?id=295a464a-6072-4e25-94e2-91be63527327
Téléchargez les sources
Solution EntLibConfig : EntLibConfig.zip (12 Ko)