Section de configuration

Configuration Designer

Introduction

Les sections de configuration ne sont pas des classes très compliquées à écrire, mais elles sont même toutes très verbeuses.

Ce document ne prétend pas vous expliquer les bases d'une bonne section de configuration, mais il vous accompagnera dans l'apprentissage de Configuration Designer.

Si les fichiers de configuration ne vous sont pas très familiers, je vous propose de consulter cet article de Nico-pyright.

Configuration Designer est un outil spécialisé dans la création de classes de configuration. Il vous guidera dans la création en vous signalant tous les petits oublis.

Vous pouvez trouver le composant ICI.

Les bases

Les fichiers de configuration dans la technologie .Net s'articulent autour d'un document XML, qui comporte la structure suivante :

Une section « configSection » qui liste les sections dans des balises « section ». Une balise section comporte deux propriétés importantes :

  • Name qui détermine le nom de la section. C'est aussi ce nom-là qui servira à appeler la section dans le code.
  • Type : contient le type de la section. Nous verrons plus bas sa structure.

A vos marques, prêt...

Pour vous accompagner tout au long de ce tutoriel, nous allons créer une application console qui nous servira d'application test.

Commençons par créer un projet console.

Vérifiez que le projet que vous avez créé utilise bien le Framework 4 et non pas le Framework 4 Profile.

Partez

Une fois le projet créé, ajoutons un nouvel élément en appuyant sur Ctrl + Shift + A.

Sélectionnez « Configuration Designer document »

Ce document contiendra toutes les informations sur les sections que vous allez créer.

Vous devez obtenir ceci.

Description de l'environnement.

  • Boite à outils.
  • Surface de travail.
  • Fichier contenant les informations.
  • L'explorateur de modèle.

La surface de travail (2) va contenir toutes nos classes sous forme graphique.

Les sections de configuration

A gauche vous avez la boite à outils. Sélectionnez le composant « Section » et glissez-le sur la surface de travail. Renommez sa propriété « Name » en « MaSection ».

Dans la fenêtre de propriété vous devez obtenir ceci :
  • La propriété Name correspond au nom de la classe quand vous y accèderez par le code.
  • La propriété Default Name correspond au nom que vous manipulerez dans le fichier XML.
  • La propriété Inheritance Modifier permet de définir si la classe est standard, abstract ou sealed.
Cliquez avec le bouton droit sur la section et ajoutez un élément « Attribute Property » que vous nommerez « ApplicationName »

Dans la fenêtre des propriétés, vous disposez d'un certain nombre de paramètres pour personnaliser votre attribut.

Ceux-ci sont rangés par catégorie.
  • Access Modifier : permet de définir son niveau d'accessibilité (public, private, protected, internal, protected internal).
  • Configuration Setting : regroupe tous les paramètres qui sont nécessaires à la gestion de la configuration dans le fichier XML.
  • Définition : Gestion de la propriété dans le code.
  • Designer : Ces propriétés sont là pour afficher des noms de propriété plus explicites dans un éditeur graphique.
  • Mode : permet de spécifier que la propriété sera gérée par un second fichier écrit manuellement dans une classe partielle.

Dans notre exemple, nous allons faire simple et laisser le type par défaut en type String.

Vous remarquerez que certaines propriétés ont été remplies par défaut à partir du nom de la propriété. Vous pouvez les personnaliser. Si vous désirez retrouver la valeur par défaut, il vous suffit de supprimer le contenu de la propriété, en quittant le texte, sa valeur par défaut réapparaitra.

Remplissons les propriétés suivantes :

  • Category : "Design"
  • Description : "Nom de l'application. "
  • Required : true

Sauvez le document.
Le composant analyse le document et détecte une erreur. En effet, le composant effectue un certain nombre de test pour vérifier la cohérence des informations. Dans le cas présent, nous avons déclaré une valeur obligatoire, il faut donc donner une valeur par défaut. Il s'agit pour ce test en particulier, du comportement par défaut mais cette validation peut être annulée.

Si vous regardez dans l'explorateur de solution, vous pouvez remarquer que fichier cgd a fait des petits.
  • Un fichier ConfigurationGenerator1.cgd.cs qui contient le code généré, destiné à être compilé.
  • Un fichier ConfigurationGenerator1.cgd.cs.xsd qui contient la structure du fichier. Ce fichier permettra de disposer de l'IntelliSense.
  • Un fichier ConfigurationGenerator1.cgd.config, contient un exemple type de configuration généré d'après les propriétés par défaut.

Ajoutons un fichier de configuration en appuyant sur Ctrl + Shift + A.

Puis éditons le fichier.

Dans la fenêtre de propriété ajoutons le schéma généré.

En théorie, il doit être dans les premiers éléments de la liste. Sélectionnez sa propriété Use sur la coche verte pour indiquer que vous voulez ajouter un schéma, puis validez avec le bouton Ok.

Dans le fichier de configuration, saisissez le texte suivant :

<?xml version="1.0" encoding="utf-8" ?>


<configuration>

<configSections>

<section name="maSection" type="ConsoleApplication1.MaSection, ConsoleApplication1"/>

</configSections>


<maSection>

</maSection>

<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/></startup>


</configuration>

La propriété « name » correspond au nom par défaut que nous avons vu dans les propriétés de la section.

La propriété type a le format suivant « type complet avec son namespace, nom du fichier ou l'on peut trouver le type.

Vous pouvez remarquer que vous avez un warning sur la balise maSection car dans notre schéma nous avions spécifié que la propriété « ApplicationName » était requise. Le document nous prévient donc qu'il comporte des erreurs.

Si vous ajoutez un espace derrière la balise MaSection, vous pouvez remarquer que l'IntelliSense vous propose la propriété manquante avec, à côté, une info bulle.

Spécifions un nom pour notre application. Passons dans le fichier Program et écrivons le code suivant :

class Program

{

static void Main(string[] args)

{

MaSection section =

(MaSection)System.Configuration.ConfigurationManager

.GetSection(MaSection.DefaultName);

     Console.WriteLine(section.ApplicationName);

}

}

Vous pouvez toutefois réduire le code écrit à ceci :

MaSection section = MaSection.Configuration;

Console.WriteLine(section.ApplicationName);

Cela revient à écrire la ligne précédente, car la class générée comprend une méthode static qui pointe sur section.

Reconnaissance des types du projet

Ajoutez maintenant une énumération dans notre code, juste en dessous de la classe program, puis compilez.
public enum MonEnumPerso

{
[Description("Description de l'enum 1")]

Enum1 = 0,

[Description("Description de l'enum 2")]

Enum2,

[Description("Description de l'enum 3")]

Enum3
}
* Ajoutez une nouvelle propriété dans la section, et renommez-la en « MyProperty ».
  • Dans la propriété Type sélectionnez le nouveau type « MonEnumPerso ».
  • Dans la propriété « Default Value » sélectionnez une valeur.
  • Puis passez la propriété Required à true.
  • Sauvez.

Ouvrez le fichier de configuration et ajoutez la nouvelle propriété, le fichier n'est plus valide car une propriété obligatoire est manquante.

Vous devez disposer de l'IntelliSense, et quand vous naviguez dans la liste de choix, vous pouvez voir la description s'afficher.

Remarque : Pour que l'outil détecte les types dans votre code, l'application doit être compilable.

Les Éléments de configuration

Dans la boite à outils, ajoutez un nouvel élément « ConfigurationElement ». Puis renommez la classe en « Log »

Dans « MaSection », sélectionnez l'attribut « MyProperty » et copiez le « Ctrl + C », puis sélectionnez le nouvel élément et collez le « Ctrl + V ».

Dans la classe « MaSection » faites bouton droit, « Add / Ref Property » et renommez la propriété en « Logs ».

Passez la propriété « Required » à true.

Passez la propriété « Type » sur Log.

Vous devez obtenir ceci :

Sauvez le document, puis ouvrez le fichier de configuration et rajoutez les propriétés manquantes. Cela doit vous donner à peu près ceci :

<maSection applicationName="AppliName" myProperty="Enum2">

<logs myProperty="Enum3"></logs>

</maSection>

Les collections

Dans certains cas, nous avons besoin que la référence à un élément pointe sur une liste. Cela se fait très simplement en glissant un composant Collection sur la surface de travail.

Dans la boite à outils, sélectionnez l'élément collection et glissez-le sur la surface de travail. Renommez-le en « ListenerCollection ».

Dans l'élément Logs faites bouton droit / Add / Ref Property puis renommez le nouvel élément en « Listeners ».

Dans la propriété type sélectionnez « ListenerCollection ».

Ajoutez un nouvel élément que vous renommerez « Listener ».

Dans la collection ListenerCollection sélectionnez la propriété « Type Item » et choisissez « Listener ».

Vous devez obtenir ceci :

Dans l'élément Listener ajoutez une propriété Name.

Et passez la propriété « Is Property Name Of » sur true.

Récapitulons :

Nous avons une classe « sectionConfiguration » qui contient une propriété Logs qui pointe sur la classe Log.

La classe Log contient une propriété qui pointe sur la classe ListenerCollection. La classe ListenerCollection est une collection de classe Listener.

La propriété qui fera office de clef dans la classe Listener est « Name ». Elle doit obligatoirement être au format texte, et elle est déterminée comme clef par sa propriété « Is Property Name Of » à true.

Les valideurs

Sur la section Cliquez sur la propriété « ApplicationName ».

Editez sa propriété « Validator ».

Sélectionnez le bouton vert « Add attribute » et choisissez « StringValidatorAttribute ».

Cliquez sur « Add parameter » et choisissez « InvalidCharacters » puis saisissez « &#//_-('=)àç_ »

Personnalisez les autres propriétés comme sur le schéma.

Les TypeConverters

Par défaut, les fichiers de configuration ne savent gérer que les types de base. Pour le reste, il y a les « TypeConverter ». Le mécanisme est assez simple, dans le cas où la conversion d'un type string ne possède pas de cast implicit ou explicit, le Framework vérifie s'il existe un attribut « TypeConverterAttribute ». Si c'est le cas il sera appelé pour convertir la donnée.

Nous allons mettre ce mécanisme en évidence en le testant :

Dans la class « Listener » ajoutez un attribut « Bouton droit / Add /Attribute property » et renommez- le en « Provider ».

Dans la propriété type sectionnez « Type ».

Dans la propriété « Type Converter » selectionnez « System.Configuration.TypeNameConverter ».

Sauvez le document.

Ce type TypeConverter assurera la transformation de la propriété au format texte dans le fichier de configuration en Type.

Ouvrez le fichier de configuration. Puis dans la section listener ajoutez un attribut type.

<maSection

    name="Name of the listener"

    type="System.Diagnostics.DefaultTraceListener, System.Diagnostics" />

La convention pour écrire un type au format texte est de spécifier le type complet avec son namespace, puis séparé par une virgule le nom du fichier sans l'extension. Si vous avez des difficultés pour l'écrire vous pouvez lire la propriété AssemblyQualidiedName. Pour plus d'information sur concept vous pouvez trouver la documentation ICI.

Les Using Namespace

Quand l'utilitaire doit ramener des listes de type ou de namespace, il ne ramène que les types connus, c'est-à-dire le namespace dans lequel se trouve le fichier cgd, et le namespace System.configuration.

Vous pouvez bien sûr en ajouter d'autres. Quand vous vous trouvez sur la surface de travail, vous activez également la fenêtre « Configuration Generator Explorer ».

Modifiez le fichier Program pour qu'il corresponde au code suivant, puis recompilez le projet.

namespace ConsoleApplication1
{
  class Program
  {
    static void Main(string[] args)
   {
      MaSection section = MaSection.Configuration;
      Console.WriteLine(section.ApplicationName);
    }
  }
  namespace Perso
  {
    public enum MonEnumPerso
    {
      [Description("Description de l'enum 1")]
      Enum1 = 0,
      [Description("Description de l'enum 2")]
      Enum2,
      [Description("Description de l'enum 3")]
      Enum3
    }
  }
}

Vous remarquerez que le Type MonEnumPerso n'est plus dans le namespace ConsoleApplication1, mais dans ConsoleApplication1.Perso.

Cela veut dire que si vous recompilez l'application, vous ne verrez plus le type dans la liste de sélection des types. Pour le voir à nouveau dans la liste de type, vous devez ajouter un namespace de recherche.

Voici comment faire :

Le code généré ne correspond plus aux objets du code existant, ce qui produit deux erreurs. Nous avons un souci car pour changer la référence dans l'outil et trouver le bon type, il faut que l'application puisse compiler, mais elle ne compilera pas temps que nous n'aurons pas les bons objets.

Sélectionnez la surface et dans les propriétés Passez « Generate code » sur false, sauvez le document, recompilez.

Vous pouvez remarquer les sections Usings qui listent les namespaces supplémentaires.

Vous trouverez une section sur chaque élément, ainsi qu'une autre sur le modèle qui couvre la totalité des objets.

Sélectionnez la section « Configuration Model » puis clique droit « Add New Using Namespace »
Une fois le using créé , tapez le nom du namespace dans sa propriété Fullname ou cliquez sur le bouton de l'éditeur.

Maintenant, vous pouvez aller modifier les deux propriétés qui pointaient sur l'ancien type. Pensez à bien corriger la valeur par défaut. Mais si vous oubliez l'outil se chargera de vous rappeler que la valeur n'est pas cohérente.

Conclusion

Voici une rapide présentation de cet outil qui se veut le plus simple possible. Vous pouvez m'envoyer vos remarques à l'adresse suivante : gaelgael5@gmail.com

Remerciements

Je voudrais remercier Alain Medge, pour son aide sur toutes les petites choses qui ne sont pas forcements évidentes à trouver, et ma femme pour la relecture de ce document.

Ce document intitulé « Section de configuration » issu de CodeS SourceS (codes-sources.commentcamarche.net) est mis à disposition sous les termes de la licence Creative Commons. Vous pouvez copier, modifier des copies de cette page, dans les conditions fixées par la licence, tant que cette note apparaît clairement.