SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

japan.internet.com翻訳記事

柔軟な.NET構成セクションハンドラ(.config)の作成

構成セクションハンドラのカスタマイズ

  • X ポスト
  • このエントリーをはてなブックマークに追加

ダウンロード ソースコード (56.4 KB)

C#を使用して柔軟な構成セクションハンドラを作成する方法を説明します。.NET構成システムの背景を簡単に紹介し、このシステムが有益である理由と、このシステムを拡張する方法について説明します。

  • X ポスト
  • このエントリーをはてなブックマークに追加

はじめに

 本稿では、C#を使用して柔軟な構成セクションハンドラを作成する方法を説明します。.NET開発者ならば、構成セクションハンドラを記述した経験が何度かあるでしょう。まず.NET構成システムの背景を簡単に紹介し、このシステムが有益である理由と、このシステムを拡張する方法について説明します。

構成システムの背景と概念

 .NET構成システムの目的は単純で、構成情報を読み書きするための一貫した方法を開発者に提供することです。かつてのXML開発者は、一般的には初期設定ファイル(.ini)、データベース、または独自の構成形式を使用していました。現在の開発者は、構成インターフェイスを実装し、それに応じて構成ハンドラを記述するだけで済みます。

 .NET構成システムには、.NET構成設定にプログラム的にアクセスするためのクラスがいくつか用意されています。System.Configuration.ConfigurationSettingsは、開発者が構成ファイルにアクセスするためのクラスです。このクラスのインターフェイスは非常に単純です。AppSettingsプロパティは<AppSettings>構成セクションを公開するので、開発者はキー/値の形式に基づいて設定を取得することができます。このクラスには、GetConfig(sectionName)というメソッドも含まれています。開発者はこのメソッドを使用して、特定のセクションの構成設定を要求できます。さらに、構成フレームワークを使用して、独自の構成セクションとハンドラを作成することもできます。構成設定は、System.Configuration.IConfigurationSectionHandlerインターフェイスを実装しているセクションハンドラによって作成されます。このインターフェイスはCreateメソッドを公開しています。開発者はこのCreateメソッドを利用して、特定セクションのXMLだけを設定オブジェクトに変換することができます。このメソッドにより、開発者は構成ファイルの所在、構成ファイル内での特定セクションの解析、ファイルのオープン/クローズといった詳細を気にせずに済みます。Createメソッドから返されたオブジェクトは、適切な設定オブジェクトに変換またはキャストできます。

構成セクションハンドラの作成

 開発を行っていると、実行時に構成システムから値を取得しなければならない場面にたびたび遭遇します。私の所属チームが最近作成したいくつかのWebアプリケーションは、すべてのページを1つのクラスから継承して作成するという方法をとっていました。このクラス内では、認証(authentication)、許可(authorization)、ページレイアウトを扱っていました。それぞれのアプリケーションの見た目はCSSで変えていましたが、使用しているHTMLコードは同じでした。我々はこのしくみを実現するために、スタイルシートを関連付けたオブジェクトをいくつか作成し、それを利用して、ページに組み込むスタイルシートを動的に設定していました。本稿ではこの例を使用して、構成ハンドラのさまざまな利用方法を具体的に説明していきたいと思います。

概要

 基本ページクラスでは、ページに組み込むスタイルシートを構成ファイルで変更できるようにしたいと考えました。これを実現する手段として、StyleSheetクラス、StyleSheetCollectionクラス、StyleSheetSettingクラスを作成しました。StyleSheetクラスには、NameHrefMediaという3つの単純な文字列プロパティを用意しました。StyleSheetCollectionクラスはCollectionBaseから継承して作成し、複数のStyleSheetオブジェクトを使い慣れた方法で格納できるようにしました。StyleSheetSettingクラスには、StyleSheetsというStyleSheetCollection型プロパティを用意しました。

 StyleSheetSettingクラスは、構成ファイル内のセクションを表すオブジェクト表現です。

セクションハンドラの実行

 たいていの開発者は、構成セクションハンドラを特定の構成セクションごとに別々に記述しようと考えます(私もそうでした)。しかし、IConfigurationSectionHandlerインターフェイスの実装パターンを一度理解してしまえば、ハンドラの作成はお決まりの退屈な作業になります。ここでは、構成セクションハンドラの基本的な作成方法を具体的に示します。リスト1は、今回のサンプルの構成ファイルのソースコードです。簡潔にするために、これ以外の構成セクションは省略してあります。この構成ファイルでは、StyleSheetSettings_1というセクションを作成し、それにBasicConfiguratorという型を割り当てています。これにより、System.Configuration.ConfigurationSettings.GetConfig("StyleSheetSettings_1")が呼び出されたらいつでもBasicConfigurator.Createメソッドを実行するよう.NET構成システムに指示しています。

リスト1
<?xmlversion="1.0"encoding="utf-8"?>
<configuration>

    <configSections>

        <sectionname="StyleSheetSettings_1"    
            type="FifteenSeconds.Core.BasicConfigurator, FifteenSeconds.Core"/>
    </configSections>

    <StyleSheetSettings_1>

        <StyleSheets>

            <StyleSheetName="Page"Href="Styles/Page.css"Media="screen"/>
            <StyleSheetName="Custom"Href="Styles/Custom.css"Media="screen"/>
            <StyleSheetName="Print"Href="/Lib/Styles/Print.css"Media="print"/>

        </StyleSheets>

    </StyleSheetSettings_1>

 </configuration>

 BasicConfigurationハンドラ内にCreateメソッドを実装します。このメソッドのソースコードをリスト2に示します。このメソッドは、StyleSheetSettings_1構成セクションの扱い方を.NET構成システムに教えるためのものです。まずStyleSheetSetting_1オブジェクトを作成します。これが、このメソッドが返す設定オブジェクトになります。次にXmlNodeListを作成し、XPathクエリを使用してセクション内のすべての<StyleSheet>ノードを選択します。このリスト内のすべてのノードを反復処理し、対応するStyleSheetオブジェクトを作成します。このオブジェクトのプロパティを、セクションXML内の属性に基づいて割り当てます。その後、これらのStyleSheetオブジェクトを、設定クラスのStyleSheetCollection型のStyleSheetsプロパティに追加します。

 この方法でも問題はありませんし、たいていの開発者はこの方法で満足するでしょう。この方法では、開発者がセクションごと、または独自に作成したオブジェクトモデルごとに新しい構成セクションハンドラを作成する必要があります。次の例では、どんな種類のオブジェクトモデルに対しても再使用できる構成セクションハンドラの記述方法を紹介します。

リスト2
public object Create(object parent, object configContext, System.Xml.XmlNode section)
{
    StyleSheetSettings_1 settings = null;
    if (section == null) { return settings; }
    settings = new StyleSheetSettings_1();
    XmlNodeList styleSheets = section.SelectNodes(@"/StyleSheets/StyleSheet");

    for (int i = 0; i < styleSheets.Count; i++)
    {
        XmlNode node = styleSheets.Item(i);
        StyleSheet styleSheet = new StyleSheet();
        styleSheet.Name = node.Attributes["Name"].InnerText;
        styleSheet.Href = node.Attributes["Href"].InnerText;
        styleSheet.Media = node.Attributes["Media"].InnerText;
        settings.StyleSheets.Add(styleSheet);
     }
     return settings;
}

XmlSerialzerConfigurationセクションハンドラ

 我々はWebアプリケーションを開発する過程で、いくつかの構成セクションハンドラを記述しました。さらに、構成ファイル内の個々のセクションに対してハンドラを書かずに済むようにするために、これらのハンドラを抽象化する方法を研究しました。その中で偶然、Craig Anderaのすばらしい記事(リンク切れ)を見つけました。Craigの記事では、XmlSerializationを使用してこの問題を解決するという方法が紹介されていました。リスト3は、その記事で扱っていた構成ファイルのコードの抜粋です。リスト4は、Craigが書いたソースコードです。

リスト3
<configuration>

    <configSections>

        <section name="StyleSheetSettings_1"    
            type="FifteenSeconds.Core.XmlConfigurator, FifteenSeconds.Core"/>
    </configSections>
    <StyleSheetSettings_1
configuratorType="FifteenSeconds.Core.StyleSheetSettings_1, FifteenSeconds.Core">
        
        <StyleSheets>
            <StyleSheet Name="Page" Href="/Lib/Styles/Page.css" Media="screen"/>
            <StyleSheet Name="Custom" Href="/Lib/Styles/Custom.css" Media="screen"/>
            <StyleSheet Name="Print" Href="/Lib/Styles/Print.css" Media="print"/>
        </StyleSheets>     

    </StyleSheetSettings_1>
リスト4
public object Create(object parent, object configContext, System.Xml.XmlNode section)
{
    Object settings = null;
    if (section == null) { return settings; }
    XPathNavigator navigator = section.CreateNavigator();
    
    String typeName = (string)navigator.Evaluate("string(@configuratorType)");
    
    Type sectionType = Type.GetType(typeName);
    XmlSerializer xs = new XmlSerializer(sectionType);
    XmlNodeReader reader = new XmlNodeReader(section);
    settings = xs.Deserialize(reader);
    return settings;
}

 構成ファイルのコードが前述の例とよく似ていることに気付くでしょう。唯一の違いはセクションにあります。この例では、configuratorTypeという属性が追加されています。これにより、XmlConfiguratorは作成する設定オブジェクトの型を実行時に判断できるようになります。XmlConfigurator.Createメソッドには、XMLを適切な設定オブジェクトにデシリアライズするコードが含まれています。このメソッドは、まずXmlNodeセクションからXPathNavigatorを作成します。次に、navigatorオブジェクトに対してEvaluateメソッドを使用し、適切な型名を取得します。その後、Type.GetType静的メソッドを使用して、その型への参照を作成します。次にXmlSerializerを作成しますが、このとき、コンストラクタにセクションの設定の型を渡します。その後、セクションXMLから作成したXmlNodeReaderXmlSerializer.Deserializeメソッドに渡します。このメソッドは、作成しようとする設定オブジェクトに対応するオブジェクトを返します。Craigのコードには含まれていませんが、Craigの記事では、XMLのSerialization属性を使用して設定オブジェクトのデシリアライズを制御するという手法についても触れられています。リスト5は、StyleSheetクラスのソースコードです。話を簡単にするために、ここでは2つのプロパティだけを含めています。StyleSheetクラスのプロパティに対応する属性を含んだStyleSheet要素で書式設定されているXMLを使用するためには、これらのパブリックプロパティを属性で修飾する必要があります。

リスト5
[XmlAttribute(DataType="string", AttributeName="Name")]
public string Name
{
          get{return _Name;}
          set{_Name = value;}
}
[XmlAttribute()]
public string Href
{
          get{return _Href;}
          set{_Href = value;}
}

 上記のコードでは、プロパティを修飾する2とおりの手法を紹介しています。1つ目の例では、属性の中でDataTypeプロパティとAttributeNameプロパティを明示的に割り当てています。これらのプロパティを省略することもできます。その場合、XmlSerializationは、これらのプロパティをシリアライズすべきものと同じ名前およびデータ型であると見なします。別の名前またはデータ型でプロパティをシリアライズしたい場合は、明示的に指定する方法が役立ちます。

 この構成セクションハンドラはオブジェクトモデルの構造に関係なく再使用できるということを証明するために、別のクラスセットを作成してみました。この例では、ServerDatabaseSecurityという3つの文字列プロパティを持つDataConnectionクラスを作成しました。パブリックプロパティステートメントではXmlAttributeを省略しました。これにより、各プロパティを構成ファイル内の要素として入力することが必要になります。リスト6に、構成XMLのソースを示します。さらに、ConnectionというDataConnection型プロパティを持つDataAccessSettingsクラスを作成しました。

リスト6
<DataAccessSettingstype="FifteenSeconds.Core.DataAccessSettings, FifteenSeconds.Core">
    <Connection>
        <Server>(local);</Server>
        <Database>FifteenSeconds;</Database>
        <Security>Integrated Security=SSPI;</Security>
    </Connection>
</DataAccessSettings>

 これが、Connectionプロパティを持つ設定オブジェクトになります。

まとめ

 本稿では、.NET構成システムの利便性を具体的に紹介しました。.NETのXmlSerialization機能を利用すると、コードを効率的に再使用することができます。Craig Anderaも述べていたとおり、構成セクションハンドラを記述するのは一度きりにしたいものです。本稿のサンプルコードには、独立したクラスライブラリを持つコンソールアプリケーションのソースコードが含まれています。

この記事は参考になりましたか?

  • X ポスト
  • このエントリーをはてなブックマークに追加
japan.internet.com翻訳記事連載記事一覧

もっと読む

この記事の著者

japan.internet.com(ジャパンインターネットコム)

japan.internet.com は、1999年9月にオープンした、日本初のネットビジネス専門ニュースサイト。月間2億以上のページビューを誇る米国 Jupitermedia Corporation (Nasdaq: JUPM) のニュースサイト internet.comEarthWeb.com からの最新記事を日本語に翻訳して掲載するとともに、日本独自のネットビジネス関連記事やレポートを配信。

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

Jeff Gonzalez(Jeff Gonzalez)

ソフトウェア開発に7年以上携わる。北米各地で活動し、高容量の商用インフラストラクチャから顧客/従業員管理システムまで幅広いプロジェクトに従事。Microsoft系のソリューションを得意とし、Microsoft、Rare Medium、Penson Financial、Fort Worth市などで重要な役割を果たす。現在はReynolds Web Solutions(旧Third Coa...

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

  • X ポスト
  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/76 2005/09/07 14:56

おすすめ

アクセスランキング

アクセスランキング

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング