Bagian app.config kustom dengan daftar sederhana dari elemen "tambahkan"

88

Bagaimana cara membuat bagian app.config kustom yang hanya berupa daftar addelemen sederhana ?

Saya telah menemukan beberapa contoh (misalnya, Bagaimana cara membuat bagian konfigurasi khusus di app.config? ) Untuk bagian khusus yang terlihat seperti ini:

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

Tetapi bagaimana cara menghindari elemen koleksi tambahan ("Perusahaan") sehingga terlihat sama dengan bagian appSettingsdan connectionStrings? Dengan kata lain, saya suka:

<registerCompanies>
  <add name="Tata Motors" code="Tata"/>
  <add name="Honda Motors" code="Honda"/>
</registerCompanies>
Joe Daley
sumber
Juga lihat stackoverflow.com/questions/1779117/…
Ohad Schneider

Jawaban:

114

Contoh lengkap dengan kode berdasarkan file konfigurasi 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>

Berikut adalah kode contoh untuk menerapkan bagian konfigurasi khusus dengan koleksi yang diciutkan

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

Berikut adalah contoh cara mengakses informasi konfigurasi dari kode.

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
sumber
@Jay Walker bagaimana Anda mengakses item yang Anda butuhkan, yaitu: - config.Instances ["Tata Motors"] apakah mungkin untuk melakukan ini?
Simon
2
Harus menunjukkan tag <configSection>harus tepat setelah <configuration>agar berfungsi!
Vedran Kopanja
3
Juga harus menunjukkan bahwa <add diperlukan. Membuat <tag kustom Anda sendiri tidak berfungsi dengan jawaban ini
Steve's a D
8
AFAIK - kode ini "config [" Tata Motors "]" tidak akan dikompilasi karena pengindeks konfigurasi dilindungi internal. Anda harus mencari cara untuk menghitung sendiri item-item dalam koleksi.
CedricB
1
@Jay semuanya baik-baik saja. The "My.MyConfiguration, My.Assembly" dalam contoh Anda untuk jenis bagian melempar saya. Saya hanya harus menggunakan "MyAssembly.MyConfiguration, MyAssembly" untuk apa yang saya coba.
Glen
38

Tidak ada bagian konfigurasi khusus yang diperlukan.

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>

Ambil

// 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
sumber
1
Saya kira itu tidak secara ketat menjawab pertanyaan OP, tetapi saya pikir ini adalah solusi yang valid, dan yang jauh lebih sederhana. Setidaknya itu membantu saya!
styl0r
2
@ stylvell Anda benar. itu tidak benar - benar menjawabnya. Jika Anda harus menggunakan nama / kode atribut alih-alih kunci / nilai solusi saya, Anda harus menggunakan bagian yang benar-benar khusus. Namun, saya menganggap Anda mengendalikan file konfigurasi, dan memiliki hal-hal yang lebih baik untuk dilakukan daripada membuat kelas khusus.
JJS
4
Sangat sederhana dan bersih! Tidak perlu bloatware bagian / elemen kustom tambahan.
Ondřej
2
Anda juga dapat memperbarui ke Versi = 4.0.0.0 jika Anda ingin hanya dengan mengubah nomor versi. Ini adalah jawaban terbaik jika Anda hanya membutuhkan daftar sederhana tambahan. Hal yang sama juga dapat dilakukan untuk "System.Configuration.ConnectionStringsSection", meskipun duplikat ditangani sedikit berbeda dari setelan aplikasi.
Sharpiro
@Sharpiro, apakah Anda mengalami masalah dengan versi perakitan? Saya pikir pengikatan perakitan akan berjalan cepat, bahkan untuk versi kerangka kerja yang lebih baru.
JJS
22

Berdasarkan jawaban Jay Walker di atas, berikut adalah contoh kerja lengkap yang menambahkan kemampuan untuk melakukan pengindeksan:

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

Berikut adalah kode contoh untuk menerapkan bagian konfigurasi khusus dengan koleksi yang diciutkan

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

Berikut adalah contoh cara mengakses informasi konfigurasi dari kode.

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
sumber
2
Ini bagus. Sekarang kita hanya perlu kode contoh untuk memperbarui, menambah, dan menghapus sebuah Instance.
Scott Hutchinson
1
Terima kasih atas solusinya! Siapa pun yang membuat ini di MS ... ini benar-benar rumit yang tidak perlu.
Switch386
8

Berdasarkan jawaban Jay Walker, mengakses elemen perlu dilakukan dengan melakukan iterasi melalui koleksi "Instances". yaitu.

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

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