Bonnes pratiques pour stocker des informations dans les fichiers de configuration

Lors du développement d’une application, il est courant de stocker des informations dans les fichiers de configuration, que ce soit « app.config » pour les clients lourds, ou « web.config » pour les applications web.

La méthode la plus simple pour stocker ces informations est d’utiliser la section « AppSettings ».

<AppSettings>
  <add key="ContactMail" value="contact@mcnext.com" />
</AppSettings>

 

string mail = ConfigurationManager.AppSettings["ContactMail"];

C’est une manière pratique de conserver des données qui pourront être facilement modifiées en production, car ces fichiers ne sont pas compilés.

Malheureusement, on constate souvent que ces données ont tendance à s’empiler au fur et à mesure que le développement avance, au point de se retrouver parfois avec d’interminables sections « AppSettings ».

Première alternative : créer ses propres SectionHandler

Une alternative à ce problème est de créer ses propres sections de configuration. Il faut pour cela créer une classe qui hérite de ConfigurationSection.

namespace ApplicationNamespace
{
    public class ContactSectionHandler : ConfigurationSection
    {
        [ConfigurationProperty("Mail", IsRequired = true)]
        public string Mail
        {
            get
            {
                return (string)this["Mail"];
            }
        }
    }
}

 

<configuration>
  <configSections>
    <section name="contact" type="ApplicationNamespace.ContactSectionHandler, NomDeLAssembly" />
  </configSections>
  <contact Mail="contact@mcnext.com" />
</configuration>

L’accès aux données se faisant ensuite tout aussi simplement qu’avec « AppSettings » :

string mail = ((ContactSectionHandler)ConfigurationManager.GetSection("contact")).Mail;

Ces sections de configuration personnalisées peuvent aussi contenir des collections de pairs clef/valeur. Cela se fait en créant une classe qui hérite de ConfigurationElementCollection pour représenter la collection, et une autre classe qui hérite de ConfigurationElement pour représenter un élément de cette collection. On peut alors obtenir ce type de représentations :

<contacts>
  <contact nom="Hémery" prenom="Pierre-Yves" fonction="Directeur du Pôle .NET" mail="pole-dotnet@mcnext.com" />
  <contact nom="Baduel" prenom="Roch" fonction="Directeur du Pôle Biztalk" mail="pole-biztalk@mcnext.com" />
</contacts>

Expliquer dans le détail comment créer ces sections de configuration personnalisées serait un peu long. Je vous invite à vous reporter à la documentation sur MSDN pour obtenir des informations supplémentaires. Car ce qui nous intéresse ici, c’est la seconde alternative : celle qui permet de ne pas avoir à créer de section personnalisées, tout en évitant de se retrouver avec des fichiers de configuration où tout est mélangé.

Seconde alternative : utiliser les SectionHandler « clefs en main »

Une alternative peu connue et beaucoup plus simple que la création de sections personnalisées est l’utilisation des SectionHandler « clefs en main » fournis en standard dans le Framework .NET. Ceux-ci sont au nombre de trois :

  • SingleTagSectionHandler, qui permet de créer une section simple contenant des attributs.
  • NameValueSectionHandler, qui permet de créer une collection de paires clef/valeur, où chaque clef peut être répétée plusieurs fois.
  • DictionarySectionhandler, qui permet de créer une collection de paires clef/valeur, où chaque clef doit être unique.

Il faut tout d’abord déclarer ces sections dans le nœud « configuration/configSections » :

<configuration>
  <configSections>
    <!-- Les noms donnés à chaque section sont purement arbitraires -->
    <section name="singleSection" type="System.Configuration.SingleTagSectionHandler" />
    <section name="nameValueSection" type="System.Configuration.NameValueSectionHandler" />
    <section name="dictionarySection" type="System.Configuration.DictionarySectionHandler" />
  </configSections>
  <!-- ... -->
</configuration>

Il ne reste ensuite plus qu’à utiliser ces sections :

<singleSection nom="Hémery" prenom"Pierre-Yves" fonction="Directeur du Pôle .NET" mail="pole-dotnet@mcnext.com" />
<nameValueSection>
  <add key="ValeurEnDouble" value="toto" />
  <add key="ValeurEnDouble" value="titi" />
  <add key="AutreValeur" value="foobar" />
</nameValueSection>
<dictionarySection>
  <add key="DRH" value="drh@mcnext.com" />
  <add key="CONTACT" value="contact@mcnext.com" />
</dictionarySection>

La récupération des données dans le code C# se fait là encore très facilement. SingleTagSectionHandler et DictionarySectionHandler vous renverront une Hashtable, tandis que NameValueSectionHandler vous renverra une NameValueCollection.

string mail = ((Hashtable)ConfigurationManager.GetSection("singleSection"))["mail"];
// valeurEnDouble aura la valeur "toto,titi" (nos deux valeurs séparées par une virgule)
string valeurEnDouble = ((NameValueCollection)ConfigurationManager.GetSection("nameValueSection"))["ValeurEnDouble"];
string drh = ((Hashtable)ConfigurationManager.GetSection("dictionarySection"))["DRH"];

Comme on le voit, ces SectionHandler « clefs en main » permettent d’organiser très simplement les données stockées dans les fichiers de configuration, sans avoir à en passer par l’exercice souvent fastidieux de la création de sections personnalisées.

Une autre bonne pratique qu’il est bon de noter est d’encapsuler l’accès à ces données dans des classes statiques, et d’y gérer l’éventuelle levée d’exceptions. Par exemple en contrôlant qu’une certaine clef existe bel et bien.

public static class ConfigurationData
{
    private static readonly Hashtable _sectionDatabaseAccess = (Hashtable)ConfigurationManager.GetSection("databaseAccess");

    public static int Timeout
    {
        get
        {
            if (_sectionDatabaseAccess.ContainsKey("timeout"))
            {
                int val;
                if (!int.TryParse(_sectionDatabaseAccess["timeout"].ToString(), out val))
                    throw new Exception(@"La clef ""timeout"" de la section ""databaseAccess"" doit stocker un nombre entier.");

                return val;
            }

            throw new Exception(@"La section de configuration ""databaseAccess"" devrait contenir une valeur pour la clef ""timeout"".");
        }
    }
}

L’accès aux données s’en trouve nettement facilité :

int timeout = ConfigurationData.Timeout;

Laisser un commentaire

Entrez vos coordonnées ci-dessous ou cliquez sur une icône pour vous connecter:

Logo WordPress.com

Vous commentez à l'aide de votre compte WordPress.com. Déconnexion / Changer )

Image Twitter

Vous commentez à l'aide de votre compte Twitter. Déconnexion / Changer )

Photo Facebook

Vous commentez à l'aide de votre compte Facebook. Déconnexion / Changer )

Photo Google+

Vous commentez à l'aide de votre compte Google+. Déconnexion / Changer )

Connexion à %s