ASP.NET で web.config に 高度な カスタム設定 を 定義する方法

0 件のコメント

アプリケーション構成ファイル(アプリケーション設定ファイル) に対して 独自の構成(カスタム構成) を実装する際、単純な要素と属性以外の設定方法を 3種類 取り上げます。 "高度な"と言っても、ここで取り上げるトピックは 基本(単純な要素) と 配列 、 型変換 になります。 カスタム設定 に対する 検証 も行えるようですが…少しボリュームが大きくなったので別記事「ASP.NET で web.config の カスタム設定 を 検証 する 方法」にしました。

目次

カスタムエレメント

カスタムエレメント の 作成

以下のコードにより、 要素("GreetingConfigElement") / @message のような属性が記述できるようになります。

namespace WebApplication.Config
{
    using System.Configuration;

    public class GreetingConfigElement : ConfigurationElement
    {
        [ConfigurationProperty("message")]
        public string Message
        {
            get { return (string)base["message"]; }
            set { base["message"] = value; }
        }
    }
}

上位要素 への 追加

上で作成した要素を 親要素 に含め、要素名を指定します。 以下のコードにより、 親要素("ApplicationConfigElement") / greeting のような 子要素 が記述できるようになります。

namespace WebApplication.Config
{
    using System.Configuration;

    public class ApplicationConfigElement : ConfigurationElement
    {
        [ConfigurationProperty("greeting")]
        public GreetingConfigElement Greeting
        {
            get { return (GreetingConfigElement)base["greeting"]; }
            set { base["greeting"] = value; }
        }
    }
}

config ファイル への 記述

上で作られた カスタム要素 を実際に config ファイル へ記載する例を以下に載せます。 上の例では カスタムセクション の作成が省かれていますが、適宜補完してください…。。

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <configSections>
    <section name="sampleSettings" type="WebApplication.Config.SampleConfigurationSection"/>
  </configSections>
  <sampleSettings>
    <application>
      <greeting message="Hello, world !" />
    </application>
  </sampleSettings>
</configuration>

カスタムコレクション

カスタムコレクション の 作成

コレクション には エレメント を保持するので、 コレクションに保存するカスタムエレメントと、リスト(コレクション)本体をの 2つ を作成します。

カスタムエレメント

"キー" とする プロパティ には、"キー (IsKey)" および "必須 (IsRequired)" を指定しておきます。

namespace WebApplication.Config
{
    using System.Configuration;

    public class ConnectionConfigElement : ConfigurationElement
    {
        [ConfigurationProperty("target", IsKey = true, IsRequired = true)]
        public string Target
        {
            get { return (string)base["target"]; }
            set { base["target"] = value; }
        }

        [ConfigurationProperty("protocol")]
        public string Protocol
        {
            get { return (string)base["protocol"]; }
            set { base["protocol"] = value; }
        }
    }
}

カスタムコレクション

ConfigurationElementCollection クラス は 抽象クラス なので、実装が必要なメソッド 2つ を記述します。 抽象メソッドの実装には、上で作成した カスタムエレメント を保持するので、該当する処理を記述します。 また、コレクションなので、便利に使えるよう、インデクサ演算子をオーバーロードします。

namespace WebApplication.Config
{
    using System.Configuration;

    public class ConnectionConfigCollection : ConfigurationElementCollection
    {
        public ConnectionConfigElement this[int index]
        {
            get
            {
                return (ConnectionConfigElement)this.BaseGet(index);
            }

            set
            {
                if (this.BaseGet(index) != null)
                {
                    this.BaseRemoveAt(index);
                }
                this.BaseAdd(index, value);
            }
        }

        protected override ConfigurationElement CreateNewElement()
        {
            return new ConnectionConfigElement();
        }

        protected override object GetElementKey(ConfigurationElement element)
        {
            return ((ConnectionConfigElement)element).Target;
        }
    }
}

上位要素 への 追加

namespace WebApplication.Config
{
    using System.Configuration;

    public class ApplicationConfigElement : ConfigurationElement
    {
        [ConfigurationProperty("connections")]
        [ConfigurationCollection(typeof(ConnectionConfigElement),
                                AddItemName = "add",
                                ClearItemsName = "clear",
                                RemoveItemName = "remove")]
        public ConnectionConfigCollection Connections
        {
            get { return (ConnectionConfigCollection)base["connections"]; }
            set { base["connections"] = value; }
        }
    }
}

config ファイル への 記述

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <configSections>
    <section name="sampleSettings" type="WebApplication.Config.SampleConfigurationSection"/>
  </configSections>
  <sampleSettings>
    <application>
      <connections>
        <add target="192.168.0.100" protocol="80" />
        <add target="192.168.0.110" protocol="80" />
      </connections> 
    </application>
  </sampleSettings>
</configuration>

型変換

カスタム設定で作成できる属性の値に対し、独自形式の文字列を指定して、その文字列からオブジェクトを生成して取り込む方法になります。 ここでは アプリケーション構成ファイル に書かれた CSV形式文字列 を List<string> 型 に変換して設定として取り込む方法を例として取り上げます。

型変換 (TypeConverter) の 作成

ConfigurationConverterBase クラス を継承して作成します。 ここでは単純な変換 (","でスプリットするだけ) しか行っていませんが、もう少し複雑な CSV を読み込む場合は 「C# で CSVファイル を List データ に 読み込む 方法」 を参照ください。 やろうと思えば JSON を記述して デシリアライズ … なんてこともできるかもしれません。

namespace WebApplication.Config
{
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Configuration;
    using System.Globalization;

    /// <summary>
    /// 構成ファイルにある文字列 (CSV形式文字列) と List&lt;string&gt; 型 との間の変換をします。
    /// </summary>
    public class CsvConverter : ConfigurationConverterBase
    {
        /// <summary>
        /// コンバーターが特定の型のオブジェクトをコンバーターの型に変換できるかどうかを返します。
        /// </summary>
        /// <param name="ctx">型変換に使用される ITypeDescriptorContext オブジェクト。</param>
        /// <param name="type">変換前の型を表す Type。</param>
        /// <returns>変換できる場合は true。それ以外の場合は false。</returns>
        public override bool CanConvertFrom(ITypeDescriptorContext ctx, Type type)
        {
            return type == typeof(string);
        }

        /// <summary>
        /// コンバーターがオブジェクトを指定した型に変換できるかどうかを示す値を返します。
        /// </summary>
        /// <param name="ctx">型変換に使用される ITypeDescriptorContext オブジェクト。</param>
        /// <param name="type">変換後の型を表す Type。</param>
        /// <returns>変換できる場合は true。それ以外の場合は false。</returns>
        public override bool CanConvertTo(ITypeDescriptorContext ctx, Type type)
        {
            return type == typeof(string);
        }

        /// <summary>
        /// 指定したコンテキストとカルチャ情報を使用して、指定したオブジェクトをコンバーターの型に変換します。
        /// 構成ファイルに書かれた文字列情報をデシリアライズしてオブジェクトを生成します。
        /// </summary>
        /// <param name="context">書式指定コンテキストを提供する ITypeDescriptorContext。</param>
        /// <param name="culture">現在のカルチャとして使用する CultureInfo。</param>
        /// <param name="value">変換対象の Object。</param>
        /// <returns>変換後の値を表す Object。</returns>
        public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
        {
            var raw = (string)value;
            var list = new List<string>(raw.Split(','));

            return list;
        }

        /// <summary>
        /// 指定したコンテキストとカルチャ情報を使用して、指定した値オブジェクトを、指定した型に変換します。
        /// 指定されたオブジェクトをシリアライズして構成ファイルに書き込める文字列を生成します。
        /// </summary>
        /// <param name="context">書式指定コンテキストを提供する ITypeDescriptorContext。</param>
        /// <param name="culture">CultureInfo null が渡された場合は、現在のカルチャが使用されます。 </param>
        /// <param name="value">変換対象の Object。</param>
        /// <param name="destinationType">value パラメーターの変換後の Type。</param>
        /// <returns>変換後の値を表す Object。</returns>
        public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
        {
            var list = value as List<string>;
            var data = string.Empty;
            
            if (list == null || list.Count == 0)
            {
                return data;
            }

            foreach (var item in list)
            {
                data += item + ",";
            }
            
            data.Remove(data.Length - 1, 1);

            return data;
        }
    }
}

カスタムエレメント へ 属性 として追加

カスタムエレメント の プロパティ に TypeConverter 属性 を付与し、上で作成した CsvConvereter クラス を指定します。 これにより、プリミティブ型 ではない オブジェクト へ変換が可能になります。

namespace WebApplication.Config
{
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Configuration;

    public class ApplicationConfigElement : ConfigurationElement
    {
        [ConfigurationProperty("items")]
        [TypeConverter(typeof(CsvConverter))]
        public List<string> Items
        {
            get { return (List<string>)base["items"]; }
            set { base["items"] = value; }
        }
    }
}

config ファイル への 記述

config ファイル への記載方法は 型変換 で定義した方法に従って記述します。 今回は単純な CSV形式 なので、カンマ区切り文字列を記載します。

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <configSections>
    <section name="sampleSettings" type="WebApplication.Config.SampleConfigurationSection"/>
  </configSections>
  <sampleSettings>
    <application items="a,b,c,d" />
  </sampleSettings>
</configuration>

関連記事