「追加」要素の単純なリストを含むカスタムapp.configセクション


88

単純なadd要素のリストであるカスタムapp.configセクションを作成するにはどうすればよいですか?

次のようなカスタムセクションの例(例:app.configでカスタム構成セクションを作成する方法)を見つけました。

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

しかし、余分なコレクション要素( "Companies")を避けてappSettingsconnectionStringsセクションやセクションと同じに見えるようにするにはどうすればよいですか?言い換えれば、私は次のことを望みます。

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

回答:


113

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>

折りたたまれたコレクションでカスタム構成セクションを実装するためのサンプルコードは次のとおりです

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

以下は、コードから構成情報にアクセスする方法の例です。

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必要な項目にアクセスするにはどうすればよいですか。つまり、:-config.Instances ["Tata Motors"]これは可能ですか?
Simon

1
それが機能するためには<configSection><configuration>タグの直後が正しいことを指摘する必要があります!
Vedran Kopanja 14

2
<追加が必要であることも指摘する必要があります。独自のカスタム<タグを作成しても、この回答では機能しません
スティーブはD

8
AFAIK-このコード "config [" Tata Motors "]"は、b / cをコンパイルしません。configのインデクサーは内部で保護されています。コレクション内のアイテムを自分で列挙する方法を見つける必要があります。
CedricB 2015年

1
@JayWalkerよろしくお願いします。セクションタイプの例の「My.MyConfiguration、My.Assembly」は、私を投げます。私がしようとしていることには、 "MyAssembly.MyConfiguration、MyAssembly"を使用する必要がありました。
グレン

38

カスタム構成セクションは必要ありません。

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>

取得する

// 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
それはOPの質問に厳密に答えるものではないと思いますが、私はそれが有効な解決策であり、はるかに簡単な解決策だと思います。少なくともそれは私を助けました!
styl0r 2016

2
@ styl0rあなたは正しい。厳密には答えません。私のソリューションのキー/値の代わりに属性の名前/コードを使用する必要がある場合は、真にカスタムなセクションを使用する必要があります。ただし、私はあなたが設定ファイルを制御していると想定し、カスタムクラスを作成するよりも実行することをお勧めします。
JJS 2016

4
とてもシンプルできれい!追加のカスタムセクション/エレメントブロートウェアは必要ありません。
オンドレイ

2
バージョン番号を変更するだけで、必要に応じてVersion = 4.0.0.0に更新することもできます。追加の単純なリストが必要な場合は、これが最良の答えです。「System.Configuration.ConnectionStringsSection」についても同じことができますが、重複の処理はアプリの設定とは少し異なります。
Sharpiro

@Sharpiroアセンブリバージョンに問題がありましたか?フレームワークの新しいバージョンであっても、アセンブリバインディングは適切なものであると思いました。
JJS

21

上記のJay Walkerの回答に基づいて、これはインデックス作成を実行する機能を追加する完全に機能する例です。

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

折りたたまれたコレクションでカスタム構成セクションを実装するためのサンプルコードは次のとおりです

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

以下は、コードから構成情報にアクセスする方法の例です。

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
これは素晴らしい。これで、インスタンスを更新、追加、削除するためのサンプルコードが必要になります。
Scott Hutchinson

1
解決策をありがとう!MSでこれを作った人は誰でも...これは本当に不必要に複雑です。
Switch386

8

Jay Walkerの回答に基づいて、要素へのアクセスは、「Instances」コレクションを反復することによって実行する必要があります。すなわち。

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

foreach (MyConfigInstanceElement e in config.Instances) { 
   Console.WriteLine("Name: {0}, Code: {1}", e.Name, e.Code); 
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.