• 20 heures
  • Moyenne

Ce cours est visible gratuitement en ligne.

Vous pouvez obtenir un certificat de réussite à l'issue de ce cours.

J'ai tout compris !

Mis à jour le 10/03/2017

Configurez votre application

Connectez-vous ou inscrivez-vous gratuitement pour bénéficier de toutes les fonctionnalités de ce cours !

Dans le cycle de vie d'une application, il est fréquent que de petites choses changent. Imaginons que mon application doive se connecter à un serveur FTP pour sauvegarder les données sur lesquelles j'ai travaillé. Pendant mes tests, effecutés en local, mon serveur FTP pourrait avoir l'adresse ftp://localhost avec un login et un mot de passe test. Évidemment, lors de l'utilisation réelle de mon application, l'adresse changera, et le login et le mot de passe varieront en fonction de l'utilisateur.
Il faut être capable de changer facilement ces paramètres sans avoir à modifier le code ni à recompiler l'application.

C'est là qu'interviennent les fichiers de configuration : ils permettent de stocker toutes ces petites choses qui servent à faire varier notre application. Pour les clients lourds, comme nos applications console, il s’agit du fichier app.config : un fichier XML qui contient la configuration de notre application. Il stocke des chaînes de connexion à une base de données, une url de service web, des préférences utilisateurs, etc. Bref, tout ce qui va permettre de configurer notre application !

Rappel sur les fichiers XML

Vous ne connaissez pas les fichiers XML ? Si vous voulez en savoir plus, n’hésitez pas à faire un petit tour sur internet, c’est un format très utilisé dans l’informatique.
Pour faire court, le fichier XML est un langage de balise, un peu comme le HTML, où l’on décrit de l’information. Les balises sont des valeurs entourées de < et > qui décrivent la sémantique de la donnée. Par exemple :

<prenom>Nicolas</prenom>

La balise <prenom> est ce qu’on appelle une balise ouvrante, cela signifie que ce qui se trouve après (en l’occurrence la chaine « Nicolas ») fait partie de cette balise jusqu’à ce que l’on rencontre la balise fermante </prenom> qui est comme la balise ouvrante à l’exception du / précédant le nom de la balise.
Le XML est un fichier facile à lire par nous autres humains. On en déduit assez facilement que le fichier contient la chaine « Nicolas » et qu’il s’agit sémantiquement d’un prénom.
Une balise peut contenir des attributs permettant de donner des informations sur la donnée. Les attributs sont entourés de guillemets " et " et font partis de la balise. Par exemple :

<client nom="Nicolas" age="30"></client>

Ici, la balise client possède un attribut « nom » ayant la valeur « Nicolas » et un attribut « age » ayant la valeur « 30 ». Encore une fois, c’est très facile à lire pour un humain.
Il est possible que la balise n’ait pas de valeur, comme c’est le cas dans l’exemple ci-dessus. On peut dans ce cas-là remplacer la balise ouvrante et la balise fermante par cet équivalent :

<client nom="Nicolas" age="30"/>

Enfin, et nous allons terminer notre aperçu rapide du XML avec un dernier point. Il est important de noter que le XML peut imbriquer ses balises et qu’il ne peut posséder qu’un seul élément racine, ce qui nous permet d’avoir une hiérarchie de données. Par exemple nous pourrons avoir :

<listesDesClient>
  <client type="Particulier">
    <nom>Nicolas</nom>
    <age>30</age>
  </client>
  <client type="Professionel">
    <nom>Jérémie</nom>
    <age>40</age>
  </client>
</listesDesClient>

On voit tout de suite que le fichier décrit une liste de deux clients. Nous en avons un qui est un particulier, qui s’appelle Nicolas et qui a 30 ans alors que l’autre est un professionnel, prénommé Jérémie et qui a 40 ans.

Créer le fichier de configuration

Pourquoi utiliser un fichier de configuration ?

  • pour éviter de mettre des valeurs en dur dans le code. Imaginons que nous utilisions une url de service web dans notre application, si l'url change, on aimerait ne pas avoir à recompiler le code.

  • pour éviter d'utiliser la base de registre comme cela a beaucoup été fait dans les premières versions de Windows et de donner les droits de modification de base de registre.

Ces fichiers permettent d’avoir des informations de configuration, potentiellement typées. De plus, le framework .NET dispose de méthodes pour y accéder facilement.
L'intérêt d'utiliser un fichier XML plutôt qu'un fichier binaire est que ce fichier est lisible et compréhensible facilement. On peut également le modifier à la main sans un système évolué permettant de faire des modifications.
Voilà plein de raisons pour lesquelles on va utiliser ces fichiers.

Déjà, premièrement vérifiez que ce fichier n'est pas déjà présent :

Vérification de la présence du fichier de configuration
Vérification de la présence du fichier de configuration

S'il ne l'est pas, alors pour ajouter ce fichier de configuration : faisons un clic droit sur le projet Ajouter > Nouvel élément :

Ajouter un nouvel élément
Ajouter un nouvel élément

Et choisissons le modèle de fichier Fichier de configuration de l’application :

Ajouter un nouveau fichier de configuration
Ajouter un nouveau fichier de configuration

Gardez lui son nom et validez sa création.
S'il est nouveau, ce fichier est presque vide (sinon, ignorez ce qu'il y a déjà dedans) :

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

Il possède sur sa première ligne un marqueur permettant d’identifier le fichier comme étant un fichier XML et une balise ouvrante configuration, suivie de sa balise fermante.

C’est la structure de base du fichier de configuration. Nous mettrons nos sections de configuration à l’intérieur de cette balise.
Nous retrouvons notre fichier de configuration dans notre projet et nous pouvons le voir dans l’explorateur de documents :

Image utilisateur

Compilons notre application et rendons-nous dans le répertoire où le fichier exécutable est généré. Nous y trouvons également un fichier qui porte le même nom que notre exécutable et dont l’extension est .exe.config. C’est bien notre fichier de configuration. Visual Studio Express le déploie au même endroit que notre application et lui donne un nom qui va lui permettre d’être exploité par notre application. Pour être utilisables, ces fichiers doivent se situer dans le même répertoire que l'exécutable.

Lecture simple dans la section de configuration prédéfinie : AppSettings

Avoir un fichier de configuration, c’est bien. Mais il faut savoir lire à l’intérieur si nous souhaitons pouvoir l’exploiter.
Il existe plusieurs façons d’indiquer des valeurs de configuration, nous les découvrirons tout au long de ce chapitre.
La plus simple est d’utiliser la section « AppSettings ». C'est une section où on peut mettre, comme son nom le suggère aux anglophones, les propriétés de l'application. Pour cela, on utilisera un système de clé / valeur pour stocker les informations.
Par exemple, modifiez le fichier de configuration pour avoir :

<configuration>
  <appSettings>
    <add key="prenom" value="nicolas"/>
    <add key="age" value="30"/>
  </appSettings>
</configuration>

En voyant ce fichier de configuration, l’être humain comprend assez facilement que nous allons avoir deux paramètres de configuration. Un premier qui est le prénom et qui va valoir Nicolas. Un deuxième qui est l’âge et qui sera de 30.
Le savoir en tant qu’être humain, c’est bien. Pouvoir y accéder dans notre programme informatique, c’est encore mieux. :)

Voyons comment faire.
La première chose à faire est de référencer, si ce n’est déjà fait, l’assembly qui contient toutes les classes permettant de gérer la configuration. Elle s’appelle (sans surprise) System.Configuration :

Référencer l'assembly qui permet de gérer les fichiers de configuration
Référencer l'assembly qui permet de gérer les fichiers de configuration

Pour accéder au fichier de configuration, nous allons utiliser la classe statique ConfigurationManager. Pour accéder aux informations contenues dans la section AppSettings, nous utiliserons sa propriété AppSettings. Et nous pourrons accéder aux éléments de la configuration en utilisant l’opérateur d’indexation : [].
Ce qui donne :

string prenom = ConfigurationManager.AppSettings["prenom"];
string age = ConfigurationManager.AppSettings["age"];

Console.WriteLine("Prénom : " + prenom + " / Age : " + age);

On peut également utiliser des index numériques pour y accéder, mais je trouve que cela manque vraiment de clarté :

string prenom = ConfigurationManager.AppSettings[0];
string age = ConfigurationManager.AppSettings[1];

Console.WriteLine("Prénom : " + prenom + " / Age : " + age);

De plus, cela oblige à connaître l’ordre dans lequel les clés ont été mises dans le fichier.
Il est possible aussi de boucler sur toutes les valeurs contenues dans la section :

foreach (string cle in ConfigurationManager.AppSettings)
{
    Console.WriteLine("Clé : " + cle + " / Valeur : " + ConfigurationManager.AppSettings[cle]);
}

La propriété AppSettings est en fait du type NameValueCollection. Il s'agit d'une collection d'éléments de type chaine de caractères qui sont accessibles à partir d'une clé de type chaine de caractères également. Une valeur est donc associée à une clé.
À noter que la casse de la clé n’est pas importante pour accéder à la valeur associée à la clé. Le code suivant :

string prenom = ConfigurationManager.AppSettings["PRENOM"];

renverra bien notre valeur de configuration.
Cependant, si la valeur n’existe pas, nous obtiendrons la valeur null dans la chaine de caractères.
Il est important de remarquer que nous récupérons des chaines et que nous aurons besoin potentiellement de faire une conversion pour manipuler l’âge en tant qu’entier.
Rien ne vous empêche d’écrire une petite méthode d’extension maintenant que vous savez faire :

public static class ConfigurationManagerExtensions
{
    public static int ObtenirValeurEntiere(this NameValueCollection appSettings, string cle)
    {
        string valeur = appSettings[cle];
        return Convert.ToInt32(valeur);
    }
}

Que nous pourrons utiliser avec :

int age = ConfigurationManager.AppSettings.ObtenirValeurEntiere("age");

Lecture des chaines de connexion à la base de données

Les chaines de connexion représentent un type de configuration particulier. Elles vont servir pour les applications ayant besoin de se connecter à une base de données. On va y stocker tout ce dont on a besoin, comme le nom du serveur ou les identifiants pour s’y connecter …
Nous y reviendrons plus en détail dans un autre cours, mais regardons la configuration suivante :

<configuration>
  <connectionStrings>
    <add name="MaConnection" providerName="System.Data.SqlClient"
      connectionString="Data Source=.\SQLEXPRESS; Initial Catalog=Base1; Integrated Security=true"/>
    <add name="MaConnection2" providerName="System.Data.SqlClient"
      connectionString="Data Source=.\SQLEXPRESS; Initial Catalog=Base2; Integrated Security=true"/>
  </connectionStrings>
</configuration>

Nous définissons ici deux chaines de connexion qui permettent de se connecter en authentification Windows (Integrated Security=true) sur un serveur hébergé en local (.\SQLEXPRESS) dont le nom est SQLEXPRESS, qui utilisent SQL SERVER (providerName="System.Data.SqlClient), qui pointent sur les bases de données Base1 et Base2, identifiées chacune par les noms MaConnection et MaConnection2.
Pour obtenir les informations de configuration individuellement, il faudra utiliser la propriété ConnectionStrings de la classe ConfigurationManager en y accédant par leurs noms :

ConnectionStringSettings chaineConnexion = ConfigurationManager.ConnectionStrings["MaConnection"];
Console.WriteLine(chaineConnexion.Name);
Console.WriteLine(chaineConnexion.ConnectionString);
Console.WriteLine(chaineConnexion.ProviderName);

Nous pourrons toutes les obtenir avec une boucle foreach :

foreach (ConnectionStringSettings valeur in ConfigurationManager.ConnectionStrings)
{
    Console.WriteLine(valeur.ConnectionString);
}

Créer sa propre section de configuration à partir d’un type prédéfini

Il est possible de créer sa propre section de configuration à partir d'un type prédéfini. Par exemple pour créer une section du même genre que la section appSettings, qui utilise une paire clé/valeur, on peut utiliser un DictionarySectionHandler. Il existe plusieurs types prédéfinis, que nous allons étudier ci-dessous.

DictionarySectionhandler

DictionarySectionhandler est une classe qui fournit les informations de configuration des paires clé / valeur d'une section de configuration.

Oui mais si tu nous dis que c’est un système de clé / valeur, c’est comme pour les AppSettings que nous avons vus. Pourquoi utiliser une section particulière DictionarySectionhandler alors ?

Le but de pouvoir faire des sections particulières est d'organiser sémantiquement son fichier de configuration, pour découper logiquement son fichier au lieu d'avoir tout dans la même section.
Regardons cette configuration :

<configuration>
  <configSections>
    <section name="InformationsUtilisateur" type="System.Configuration.DictionarySectionHandler" />
  </configSections>
  <InformationsUtilisateur>
    <add key="login" value="nico" />
    <add key="motdepasse" value="12345" />
    <add key="age" value="30" />
  </InformationsUtilisateur>
</configuration>

La première chose à voir est que nous indiquons à notre application que nous définissons une section de configuration du type DictionarySectionHandler et qui va s’appeler InformationsUtilisateur.
Cela permet ensuite de définir notre propre section InformationsUtilisateur, qui ressemble beaucoup à la section AppSettings sauf qu’ici, on se rend tout de suite compte qu’il s’agit d’informations utilisateur.
Pour accéder à notre section depuis notre programme, nous devrons utiliser le code suivant :

Hashtable section = (Hashtable)ConfigurationManager.GetSection("InformationsUtilisateur");

On utilise la méthode GetSection de la classe ConfigurationManager pour obtenir la section dont nous passons le nom en paramètre. On reçoit en retour une table de hachage (HashTable) et nous pourrons l’utiliser de cette façon pour obtenir les valeurs de nos clés :

Console.WriteLine(section["login"]);
Console.WriteLine(section["MOTDEPASSE"]);
Console.WriteLine(section["age"]);

Nous pouvons boucler sur les valeurs de la section en utilisant le code suivant :

foreach (DictionaryEntry d in section)
{
    Console.WriteLine("Clé  : " + d.Key + " / Valeur : " + d.Value);
}
NameValueSectionHandler

La section de type NameValueSectionHandler ressemble beaucoup à la section précédente. Observons la configuration suivante :

<configuration>
  <configSections>
    <section name="InformationsUtilisateur" type="System.Configuration.NameValueSectionHandler" />
  </configSections>
  <InformationsUtilisateur>
    <add key="login" value="nico" />
    <add key="motdepasse" value="12345" />
    <add key="age" value="30" />
  </InformationsUtilisateur>
</configuration>

C’est la même que juste précédemment, à l’exception du type de la section, qui cette fois-ci est NameValueSectionHandler. Ce qui implique que nous obtenons un type différent en retour de l’appel à la méthode GetSection, à savoir un NameValueCollection :

NameValueCollection section = (NameValueCollection)ConfigurationManager.GetSection("InformationsUtilisateur");

La récupération des informations de configuration se fait de la même façon :

Console.WriteLine(section["login"]);
Console.WriteLine(section["MOTDEPASSE"]);
Console.WriteLine(section["age"]);

Ou encore avec une boucle pour toutes les récupérer :

foreach (string cle in section)
{
    Console.WriteLine("Clé  : " + cle + " / Valeur : " + section[cle]);
}

À vous de voir lequel des deux vous préférez, mais dans tous les cas, il faudra fonctionner avec un système de clé valeur.

SingleTagSectionHandler

Ce troisième type permet de gérer une section différente des deux précédentes. Il sera possible d’avoir autant d’attributs que l’on souhaite dans la section. Prenez par exemple cet exemple de configuration :

<configuration>
  <configSections>
    <section name="MonUtilisateur" type="System.Configuration.SingleTagSectionHandler" />
  </configSections>
  <MonUtilisateur prenom="Nico" age="30" adresse="9 rue des bois"/>
</configuration>

Nous voyons que je peux mettre autant d’attributs que je le souhaite. Par contre, il ne sera possible de faire apparaitre la section « MonUtilisateur » qu’une seule fois, alors que dans les sections précédentes, nous avions une liste de clé / valeur.
Nous pourrons récupérer notre configuration avec le code suivant :

Hashtable section = (Hashtable)ConfigurationManager.GetSection("MonUtilisateur");
Console.WriteLine(section["prenom"]);
Console.WriteLine(section["age"]);
Console.WriteLine(section["adresse"]);

Attention par contre, cette fois-ci la casse est importante pour obtenir la valeur de notre attribut.
Notons notre boucle habituelle permettant de retrouver tous les attributs de notre section :

foreach (DictionaryEntry d in section)
{
    Console.WriteLine("Attribut  : " + d.Key + " / Valeur : " + d.Value);
}

Voilà pour les sections utilisant un type prédéfini.

Les groupes de sections

Super, nous savons définir des sections de configuration. Elles nous permettent d’organiser un peu mieux notre fichier de configuration. Par contre, si les sections se multiplient, cela va à nouveau être le bazar.
Heureusement, les groupes de sections sont là pour remettre de l’ordre.
Comme son nom l’indique, un groupe de section va permettre de regrouper plusieurs sections. Le but est de clarifier le fichier de configuration.
Regardons l’exemple suivant :

<configuration>
  <configSections>
    <sectionGroup name="Utilisateur">
      <section name="ParametreConnexion" type="System.Configuration.SingleTagSectionHandler" />
      <section name="InfoPersos" type="System.Configuration.DictionarySectionHandler" />
    </sectionGroup>
  </configSections>

  <Utilisateur>
    <ParametreConnexion Login="Nico" MotDePasse="12345" Mode="Authentification Locale"/>
    <InfoPersos>
      <add key="prenom" value="Nicolas" />
      <add key="age" value="30" />
    </InfoPersos>
  </Utilisateur>
</configuration>

Nous voyons ici que j’ai défini un groupe qui s’appelle Utilisateur, en utilisant la balise sectionGroup, contenant deux sections de configuration.
Remarquons plus bas le contenu des sections et nous remarquons que la balise <Utilisateur> contient nos sections de configuration comme précédemment.
Pour obtenir nos valeurs de configuration, la seule chose qui change est la façon de charger la section. Ici, nous mettons le nom de la section précédée du nom du groupe. Ce qui donne :

Hashtable section1 = (Hashtable)ConfigurationManager.GetSection("Utilisateur/ParametreConnexion");
Hashtable section2 = (Hashtable)ConfigurationManager.GetSection("Utilisateur/InfoPersos");

Après, la façon de récupérer les valeurs de configuration de chaque section reste la même.
Avouez que c’est quand même plus clair non ?

Créer une section de configuration personnalisée

Nous allons étudier rapidement comment créer des sections de configuration personnalisées. Pour cela, il faut créer une section en dérivant de la classe ConfigurationSection.
La classe ConfigurationSection permet de représenter une section d’un fichier de configuration. Donc, en toute logique, nous pouvons enrichir cette classe avec nos propriétés. Il suffit pour cela de décorer nos propres propriétés avec l’attribut ConfigurationProperty. Ce qui donne :

public class PersonneSection : ConfigurationSection
{
    [ConfigurationProperty("age", IsRequired = true)]
    public int Age
    {
        get { return (int)this["age"]; }
        set { this["age"] = value; }
    }

    [ConfigurationProperty("prenom", IsRequired = true)]
    public string Prenom
    {
        get { return (string)this["prenom"]; }
        set { this["prenom"] = value; }
    }
}

Le grand intérêt ici est de pouvoir typer les propriétés. Ainsi, nous pouvons avoir une section de configuration qui travaille avec un entier par exemple. Tout est fait par la classe mère ici et il suffit d’utiliser ses propriétés indexées en y accédant par son nom.
Pour que notre section personnalisée soit reconnue, il faut la déclarer avec notre nouveau type :

<configSections>
  <section name="PersonneSection" type="MaPremiereApplication.PersonneSection, MaPremiereApplication" />
</configSections>

Le nom du type est constitué du nom complet du type (espace de nom + nom de la classe) suivi d’une virgule et du nom de l’assembly.
Ici, l’espace de nom est le même que l’assembly car j’ai créé mes classes à la racine du projet. Si vous avez un doute, vous devez vérifier l’espace de nom dans lequel est déclarée la classe.
Ensuite, nous pourrons définir notre section, ce qui donne au final :

<configuration>
  <configSections>
    <section name="PersonneSection" type=" MaPremiereApplication.PersonneSection, MaPremiereApplication " />
  </configSections>
  <PersonneSection prenom="nico" age="30"/>
</configuration>

Pour accéder aux informations contenues dans la section, il faudra charger la section comme d’habitude :

PersonneSection section = (PersonneSection)ConfigurationManager.GetSection("PersonneSection");
Console.WriteLine(section.Prenom + " a " + section.Age + " ans");

Ce qui est intéressant de remarquer ici, c’est qu’on accède directement à nos propriétés via notre section personnalisée. Ce qui est une grande force et permet de travailler avec un entier et une chaine de caractères ici.
Il faudra faire attention à deux choses ici.
La première est la casse. Comme on l’a vu dans le code, le nom est écrit en minuscule. Il faudra être cohérent entre le nom indiqué dans l’attribut ConfigurationProperty, celui indiqué en paramètre de l’opérateur d’indexation et celui écrit dans le fichier de configuration. Tout doit être orthographié de la même façon, sinon nous aurons une exception du genre :

Image utilisateur

De même, si nous ne saisissons pas une valeur entière dans l’attribut age, il va y avoir un problème de conversion :

Image utilisateur

Créer une section personnalisée avec une collection

Dans le paragraphe du dessus, on constate qu’on ne peut définir qu’un élément dans notre section. Il pourrait être intéressant dans certains cas d'avoir une section personnalisée qui puisse contenir plusieurs éléments, par exemple pour avoir une liste de personnes.

Pour ce faire, on utilisera la classe ConfigurationPropertyCollection.
La première chose est de créer un élément en dérivant de la classe ConfigurationElement. Cet élément va ressembler beaucoup à ce qu’on a fait pour créer une section personnalisée :

public class ClientElement : ConfigurationElement
{
    private static readonly ConfigurationPropertyCollection _proprietes;
    private static readonly ConfigurationProperty age;
    private static readonly ConfigurationProperty prenom;

    static ClientElement()
    {
        prenom = new ConfigurationProperty("prenom", typeof(string), null, ConfigurationPropertyOptions.IsKey);
        age = new ConfigurationProperty("age", typeof(int), null, ConfigurationPropertyOptions.IsRequired);
        _proprietes = new ConfigurationPropertyCollection { prenom, age };
    }

    public string Prenom
    {
        get { return (string)this["prenom"]; }
        set { this["prenom"] = value; }
    }

    public int Age
    {
        get { return (int)this["age"]; }
        set { this["age"] = value; }
    }
        
    protected override ConfigurationPropertyCollection Properties
    {
        get { return _proprietes; }
    }
}

Ici, je définis deux propriétés, Prenom et Age, qui me permettent bien sûr d’y stocker un prénom et un âge qui sont respectivement une chaine de caractères et un entier. À noter que nous avons besoin de décrire ces propriétés dans le constructeur statique de la classe. Pour cela, il faut lui indiquer son nom, c’est-à-dire la chaine qui sera utilisée comme attribut dans l’élément de la section de configuration. Puis nous lui indiquons son type, pour cela on utilise le mot-clé typeof qui permet justement de renvoyer le type (dans le sens objet Type) d’un type. Enfin nous lui indiquons une option, par exemple le prénom sera la clé de mon élément (qui est une valeur unique et obligatoire à saisir) et l’âge, qui sera un élément obligatoire à saisir également.
Ensuite, nous avons besoin d’utiliser cette classe à travers une collection d’éléments. Pour ce faire, il faut créer une classe qui dérive de ConfigurationElementCollection :

public class ClientElementCollection : ConfigurationElementCollection
{
    public override ConfigurationElementCollectionType CollectionType
    {
        get { return ConfigurationElementCollectionType.BasicMap; }
    }
    protected override string ElementName
    {
        get { return "Client"; }
    }

    protected override ConfigurationPropertyCollection Properties
    {
        get { return new ConfigurationPropertyCollection(); }
    }

    public ClientElement this[int index]
    {
        get { return (ClientElement)BaseGet(index); }
        set
        {
            if (BaseGet(index) != null)
            {
                BaseRemoveAt(index);
            }
            BaseAdd(index, value);
        }
    }

    public new ClientElement this[string nom]
    {
        get { return (ClientElement)BaseGet(nom); }
    }

    public void Add(ClientElement item)
    {
        BaseAdd(item);
    }

    public void Remove(ClientElement item)
    {
        BaseRemove(item);
    }

    public void RemoveAt(int index)
    {
        BaseRemoveAt(index);
    }

    public void Clear()
    {
        BaseClear();
    }

    protected override ConfigurationElement CreateNewElement()
    {
        return new ClientElement();
    }

    protected override object GetElementKey(ConfigurationElement element)
    {
        return ((ClientElement)element).Prenom;
    }
}

Ces classes ont toujours la même structure. Ce qui est important de voir est qu’on utilise à l’intérieur la classe ClientElement pour indiquer le type de la collection. Nous indiquons également le nom de la balise qui sera utilisée dans le fichier de configuration, c’est la chaine « Client » que renvoie la propriété ElementName. Enfin, j’ai la possibilité de définir ma clé en substituant la méthode GetElementKey. Le reste des méthodes appellent les méthodes de la classe mère.

Enfin, il faut créer notre section personnalisée, qui dérive comme d’habitude de ConfigurationSection :

public class ListeClientSection : ConfigurationSection
{
    private static readonly ConfigurationPropertyCollection proprietes;
    private static readonly ConfigurationProperty liste;

    static ListeClientSection()
    {
        liste = new ConfigurationProperty(string.Empty, typeof(ClientElementCollection), null, ConfigurationPropertyOptions.IsRequired | ConfigurationPropertyOptions.IsDefaultCollection);
        proprietes = new ConfigurationPropertyCollection { liste };
    }

    public ClientElementCollection Listes
    {
        get { return (ClientElementCollection)base[liste]; }
    }

    public new ClientElement this[string nom]
    {
        get { return Listes[nom]; }
    }

    protected override ConfigurationPropertyCollection Properties
    {
        get { return proprietes; }
    }
}

Notons dans cette classe comment nous utilisons l’opérateur d’indexation pour renvoyer un élément à partir de sa clé et renvoyer la liste des éléments.
Maintenant, nous pouvons écrire notre configuration :

<configuration>
  <configSections>
    <section name="ListeClientSection" type="MaPremiereApplication.ListeClientSection, MaPremiereApplication" />
  </configSections>
  <ListeClientSection>
    <Client prenom="Nicolas" age="30"/>
    <Client prenom="Jérémie" age="20"/>
  </ListeClientSection>
</configuration>

Nous avons besoin à nouveau de définir la section en indiquant son type. Puis nous pouvons créer notre section et positionner notre liste de clients.
Pour accéder à cette section, nous pouvons charger notre section comme avant avec la méthode GetSection :

ListeClientSection section = (ListeClientSection)ConfigurationManager.GetSection("ListeClientSection");

Puis nous pouvons soit itérer sur les éléments de notre section :

foreach (ClientElement clientElement in section.Listes)
{
    Console.WriteLine(clientElement.Prenom + " a " + clientElement.Age + " ans");
}

Soit accéder à un élément à partir de sa clé :

ClientElement elementNicolas = section["Nicolas"];
Console.WriteLine(elementNicolas.Prenom + " a " + elementNicolas.Age + " ans");

ClientElement elementJeremie = section["Jérémie"];
Console.WriteLine(elementJeremie.Prenom + " a " + elementJeremie.Age + " ans");

Ce qui donnera :

Nicolas a 30 ans
Jérémie a 20 ans

Voilà pour ce petit tour sur la configuration d’une application. Nous y avons découvert plusieurs façons d’y stocker des paramètres utilisables par notre application. Il faut savoir que beaucoup de composants du framework .NET sont intimement liés à ce fichier de configuration, comme une application web créée avec ASP.NET ou lorsqu’on utilise des services web.

Il est important de remarquer que ce fichier est un fichier de configuration d’application. Il y a d’autres endroits du même genre pour stocker de la configuration pour les applications .NET, comme le machine.config qui est un fichier de configuration partagé par toutes les applications de la machine. Il y a un héritage entre les différents fichiers de configuration. Si l’on définit une configuration au niveau machine (dans le machine.config), il est possible de la redéfinir pour notre application (app.config). En général, le fichier machine.config se trouve dans le répertoire d’installation du framework .NET, c'est-à-dire dans un sous répertoire du système d’exploitation, dépendant de la version du framework .NET installée. Chez moi par exemple, il se trouve dans le répertoire : C:\Windows\Microsoft.NET\Framework\v4.0.30319\Config.

Enfin, remarquons qu’il est possible de faire des modifications du fichier de configuration directement depuis le code de notre application. C’est un point qui est rarement utilisé et que j’ai choisi de ne pas présenter pour que le chapitre ne soit pas trop long.

En résumé
  • Les fichiers de configuration sont des fichiers XML qui possèdent les paramètres de configuration de notre application.

  • Pour les applications console, ils s'appellent app.config.

  • On peut définir toutes sortes de valeurs de configuration grâce aux sections prédéfinies ou en ajoutant son propre type de section personnalisée.

Exemple de certificat de réussite
Exemple de certificat de réussite