Section app.config personnalisée avec une simple liste d'éléments «ajouter»

88

Comment créer une section app.config personnalisée qui n'est qu'une simple liste d' addéléments?

J'ai trouvé quelques exemples (par exemple, Comment créer une section de configuration personnalisée dans app.config? ) Pour des sections personnalisées qui ressemblent à ceci:

<RegisterCompanies>
  <Companies>
    <Company name="Tata Motors" code="Tata"/>
    <Company name="Honda Motors" code="Honda"/>
  </Companies>
</RegisterCompanies>

Mais comment éviter l'élément de collection supplémentaire ("Companies") pour qu'il ait le même aspect que les sections appSettingset connectionStrings? En d'autres termes, j'aimerais:

<registerCompanies>
  <add name="Tata Motors" code="Tata"/>
  <add name="Honda Motors" code="Honda"/>
</registerCompanies>
Joe Daley
la source
Voir aussi stackoverflow.com/questions/1779117/…
Ohad Schneider

Réponses:

113

Exemple complet avec code basé sur le fichier de configuration OP:

<configuration>
    <configSections>
        <section name="registerCompanies" 
                 type="My.MyConfigSection, My.Assembly" />
    </configSections>
    <registerCompanies>
        <add name="Tata Motors" code="Tata"/>
        <add name="Honda Motors" code="Honda"/>
    </registerCompanies>
</configuration>

Voici l'exemple de code pour implémenter une section de configuration personnalisée avec une collection réduite

using System.Configuration;
namespace My {
public class MyConfigSection : ConfigurationSection {
    [ConfigurationProperty("", IsRequired = true, IsDefaultCollection = true)]
    public MyConfigInstanceCollection Instances {
        get { return (MyConfigInstanceCollection)this[""]; }
        set { this[""] = value; }
    }
}
public class MyConfigInstanceCollection : ConfigurationElementCollection {
    protected override ConfigurationElement CreateNewElement() {
        return new MyConfigInstanceElement();
    }

    protected override object GetElementKey(ConfigurationElement element) {
        //set to whatever Element Property you want to use for a key
        return ((MyConfigInstanceElement)element).Name;
    }
}

public class MyConfigInstanceElement : ConfigurationElement {
    //Make sure to set IsKey=true for property exposed as the GetElementKey above
    [ConfigurationProperty("name", IsKey = true, IsRequired = true)]
    public string Name {
        get { return (string) base["name"]; }
        set { base["name"] = value; }
    }

    [ConfigurationProperty("code", IsRequired = true)]
    public string Code {
        get { return (string) base["code"]; }
        set { base["code"] = value; }
    } } }

Voici un exemple de la façon d'accéder aux informations de configuration à partir du code.

var config = ConfigurationManager.GetSection("registerCompanies") 
                 as MyConfigSection;

Console.WriteLine(config["Tata Motors"].Code);
foreach (var e in config.Instances) { 
   Console.WriteLine("Name: {0}, Code: {1}", e.Name, e.Code); 
}
Jay Walker
la source
@Jay Walker comment allez-vous accéder à l'élément dont vous avez besoin, c'est-à-dire: - config.Instances ["Tata Motors"] est-il possible de faire cela?
Simon
1
Doit souligner le <configSection>devrait être juste après la <configuration>balise pour que cela fonctionne!
Vedran Kopanja
2
Il convient également de souligner que <add est requis. Créer votre propre balise <personnalisée ne fonctionne pas avec cette réponse
Steve est un D
8
AFAIK - ce code "config [" Tata Motors "]" ne compilera pas b / c l'indexeur de config est protégé en interne. vous devrez trouver un moyen d'énumérer vous-même les éléments de la collection.
CedricB
1
@JayWalker tout va bien. Le "My.MyConfiguration, My.Assembly" dans votre exemple pour le type de section me lance. Je devais juste utiliser "MyAssembly.MyConfiguration, MyAssembly" pour ce que j'essayais.
Glen
38

Aucune section de configuration personnalisée n'est nécessaire.

App.Config

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <configSections>
        <section name="YourAppSettings" type="System.Configuration.AppSettingsSection, System.Configuration, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
    </configSections>
    <!-- value attribute is optional. omit if you just want a list of 'keys' -->
    <YourAppSettings>
        <add key="one" value="1" />
        <add key="two" value="2"/>
        <add key="three" value="3"/>
        <add key="duplicate" value="aa"/>
        <add key="duplicate" value="bb"/>
    </YourAppSettings>
</configuration>

Récupérer

// This casts to a NameValueCollection because the section is defined as a 
/// AppSettingsSection in the configSections.
NameValueCollection settingCollection = 
    (NameValueCollection)ConfigurationManager.GetSection("YourAppSettings");

var items = settingCollection.Count;
Debug.Assert(items == 4); // no duplicates... the last one wins.
Debug.Assert(settingCollection["duplicate"] == "bb");

// Just keys as per original question? done... use em.
string[] allKeys = settingCollection.AllKeys;

// maybe you did want key/value pairs. This is flexible to accommodate both.
foreach (string key in allKeys)
{
    Console.WriteLine(key + " : " + settingCollection[key]);
}
JJS
la source
1
Je suppose que cela ne répond pas strictement à la question du PO, mais je pense que c'est une solution valable et beaucoup plus simple. À tout le moins, cela m'a aidé!
styl0r
2
@ styl0r vous avez raison. il n'y répond pas strictement . Si vous devez utiliser le nom / code des attributs au lieu de ma clé / valeur de solution, vous devrez utiliser une section vraiment personnalisée. Cependant, je suppose que vous contrôlez le fichier de configuration et que vous avez mieux à faire que de créer une classe personnalisée.
JJS
4
Très simple et propre! Pas besoin de toute section / élément bloatware personnalisé supplémentaire.
Ondřej
2
Vous pouvez également mettre à jour vers Version = 4.0.0.0 si vous le souhaitez en modifiant simplement le numéro de version. C'est la meilleure réponse imo si vous avez juste besoin de listes simples supplémentaires. La même chose peut être faite pour «System.Configuration.ConnectionStringsSection» également, bien que les doublons soient traités légèrement différemment des paramètres d'application.
Sharpiro
@Sharpiro aviez-vous des problèmes avec la version d'assemblage? Je pensais que la liaison d'assemblage aurait été au rythme, même pour les nouvelles versions du framework.
JJS
21

Basé sur la réponse de Jay Walker ci-dessus, il s'agit d'un exemple de travail complet qui ajoute la possibilité de faire l'indexation:

<configuration>
    <configSections>
        <section name="registerCompanies" 
                 type="My.MyConfigSection, My.Assembly" />
    </configSections>
    <registerCompanies>
        <add name="Tata Motors" code="Tata"/>
        <add name="Honda Motors" code="Honda"/>
    </registerCompanies>
</configuration>

Voici l'exemple de code pour implémenter une section de configuration personnalisée avec une collection réduite

using System.Configuration;
using System.Linq;
namespace My
{
   public class MyConfigSection : ConfigurationSection
   {
      [ConfigurationProperty("", IsRequired = true, IsDefaultCollection = true)]
      public MyConfigInstanceCollection Instances
      {
         get { return (MyConfigInstanceCollection)this[""]; }
         set { this[""] = value; }
      }
   }
   public class MyConfigInstanceCollection : ConfigurationElementCollection
   {
      protected override ConfigurationElement CreateNewElement()
      {
         return new MyConfigInstanceElement();
      }

      protected override object GetElementKey(ConfigurationElement element)
      {
         //set to whatever Element Property you want to use for a key
         return ((MyConfigInstanceElement)element).Name;
      }

      public new MyConfigInstanceElement this[string elementName]
      {
         get
         {
            return this.OfType<MyConfigInstanceElement>().FirstOrDefault(item => item.Name == elementName);
         }
      }
   }

   public class MyConfigInstanceElement : ConfigurationElement
   {
      //Make sure to set IsKey=true for property exposed as the GetElementKey above
      [ConfigurationProperty("name", IsKey = true, IsRequired = true)]
      public string Name
      {
         get { return (string)base["name"]; }
         set { base["name"] = value; }
      }

      [ConfigurationProperty("code", IsRequired = true)]
      public string Code
      {
         get { return (string)base["code"]; }
         set { base["code"] = value; }
      }
   }
}

Voici un exemple de la façon d'accéder aux informations de configuration à partir du code.

MyConfigSection config = 
   ConfigurationManager.GetSection("registerCompanies") as MyConfigSection;

Console.WriteLine(config.Instances["Honda Motors"].Code);
foreach (MyConfigInstanceElement e in config.Instances)
{
   Console.WriteLine("Name: {0}, Code: {1}", e.Name, e.Code);
}
SwDevMan81
la source
2
C'est bien. Maintenant, nous avons juste besoin d'un exemple de code pour mettre à jour, ajouter et supprimer une instance.
Scott Hutchinson
1
Merci pour votre solution! Celui qui a fait ça à MS ... c'est vraiment inutilement compliqué.
Switch386 du
8

Sur la base de la réponse de Jay Walker, l'accès aux éléments doit être fait en itérant dans la collection "Instances". c'est à dire.

var config = ConfigurationManager.GetSection("registerCompanies") 
                 as MyConfigSection;

foreach (MyConfigInstanceElement e in config.Instances) { 
   Console.WriteLine("Name: {0}, Code: {1}", e.Name, e.Code); 
}
Bonneech
la source