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.