Sezione app.config personalizzata con un semplice elenco di elementi "aggiungi"


88

Come faccio a creare una sezione app.config personalizzata che sia solo un semplice elenco di addelementi?

Ho trovato alcuni esempi (ad esempio, come creare una sezione di configurazione personalizzata in app.config? ) Per sezioni personalizzate che assomigliano a questo:

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

Ma come faccio a evitare l'elemento di raccolta aggiuntivo ("Aziende") in modo che abbia lo stesso aspetto delle sezioni appSettingse connectionStrings? In altre parole, vorrei:

<registerCompanies>
  <add name="Tata Motors" code="Tata"/>
  <add name="Honda Motors" code="Honda"/>
</registerCompanies>

Risposte:


114

Esempio completo con codice basato sul file di configurazione 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>

Ecco il codice di esempio per implementare una sezione di configurazione personalizzata con raccolta compressa

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; }
    } } }

Ecco un esempio di come accedere alle informazioni di configurazione dal codice.

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 come fai ad accedere all'elemento di cui hai bisogno, ad esempio: - config.Instances ["Tata Motors"] è possibile farlo?
— Simon

2
Dovrebbe indicare che <configSection>dovrebbe essere subito dopo il <configuration>tag affinché funzioni!
— Vedran Kopanja

3
Dovrebbe anche sottolineare che <add è richiesto. La creazione del tuo tag <personalizzato non funziona con questa risposta
— Steve è un D

8
AFAIK - questo codice "config [" Tata Motors "]" non verrà compilato b / c l'indicizzatore di configurazione è protetto internamente. dovrai trovare un modo per enumerare da solo gli elementi della collezione.
— CedricB

1
@JayWalker tutto bene. "My.MyConfiguration, My.Assembly" nel tuo esempio per il tipo di sezione throw me. Dovevo solo usare "MyAssembly.MyConfiguration, MyAssembly" per quello che stavo tentando.
— Glen,

38

Nessuna sezione di configurazione personalizzata necessaria.

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>

Recuperare

// 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]);
}

1
Immagino che non risponda rigorosamente alla domanda dell'OP, ma penso che sia una soluzione valida e molto più semplice. Per lo meno mi ha aiutato!
— styl0r

2
@ styl0r hai ragione. non risponde rigorosamente . Se devi usare il nome / codice degli attributi invece della chiave / valore della mia soluzione, dovresti usare una sezione veramente personalizzata. Tuttavia, presumo che tu abbia il controllo del file di configurazione e che tu abbia cose migliori da fare che creare una classe personalizzata.
— JJS

4
Molto semplice e pulito! Non è necessario alcun bloatware aggiuntivo di sezione / elemento personalizzato.
— Ondřej

2
Puoi anche aggiornare alla versione = 4.0.0.0, se lo desideri, semplicemente cambiando il numero di versione. Questa è la migliore risposta imo se hai solo bisogno di semplici elenchi aggiuntivi. Lo stesso può essere fatto anche per "System.Configuration.ConnectionStringsSection", sebbene i duplicati vengano gestiti in modo leggermente diverso rispetto alle impostazioni dell'app.
— Sharpiro

@Sharpiro hai avuto problemi con la versione assembly? Pensavo che l'associazione dell'assembly sarebbe stata in linea, anche per le versioni più recenti del framework.
— JJS

22

Sulla base della risposta di Jay Walker sopra, questo è un esempio funzionante completo che aggiunge la possibilità di eseguire l'indicizzazione:

<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>

Ecco il codice di esempio per implementare una sezione di configurazione personalizzata con raccolta compressa

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; }
      }
   }
}

Ecco un esempio di come accedere alle informazioni di configurazione dal codice.

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);
}

2
Questo è fantastico. Ora abbiamo solo bisogno di un codice di esempio per aggiornare, aggiungere ed eliminare un'istanza.
— Scott Hutchinson

1
Grazie per la tua soluzione! Chiunque l'abbia fatto alla MS ... è davvero inutilmente complicato.
— Switch386

8

In base alla risposta di Jay Walker, l'accesso agli elementi deve essere eseguito iterando attraverso la raccolta "Istanze". cioè.

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

foreach (MyConfigInstanceElement e in config.Instances) { 
   Console.WriteLine("Name: {0}, Code: {1}", e.Name, e.Code); 
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.