kazuk は null に触れてしまった

C# / .NET 系技術ネタ縛りでお送りしております

Doc of Code のコードから:プロバイダパターンの実装インフラ


Doc of Code では ASP.NET のプロバイダパターンを全面的に使って、モジュール間の依存性を解決しています。

というわけで、プロバイダパターンを実装する上での内部インフラストラクチャがあったりしまして、これの軽い紹介です。

プロバイダパターンとは

ASP.NET / ADO.NET その他で色々と使われているアプリケーション内でのモジュール差し込みメカニズムと言って良いでしょうかね、APIを定義するモジュールと、実装モジュールを分ける事ができ、実装は普通に web.config とかで指定する事ができます。

素の ASP.NET 上で実装する場合には ProviderBase 派生クラスを作ります。必要であれば Initialize をオーバライドし、初期化パラメーターを受け取ります。そして ProviderSettings を保持する構成セクションを作り、 ProviderCollection を初期化てプロバイダをインスタンス化します。

そのまま普通に実装するなら、以下の様なコードになります。

public abstract class HogeProvider : ProviderBase
{
    private static Lazy<ProviderCollection> _providers = new Lazy<ProviderCollection>( InitProviderCollection );
    public static ProviderCollection Providers
    {
        get { return _providers.Value; }
    }
    private static ProviderCollection InitProviderCollection()
    {
        var collection = new ProviderCollection();
        ProvidersHelper.InstantiateProviders(
            ConfigSettings.Providers,
            collection,
            typeof(HogeProvider));
        return collection;
    }
    private static Lazy<HogeSettings> _settings = new Lazy<HogeSettings>( InitSettings );
    public HogeSettings ConfigSettings
    {
        return _settings.Value;
    }
    private static HogeSettings InitSettings()
    {
        return (HogeSettings) ConfigurationManager.GetSection(“hogeProviders”);
    }
    // API’s goes here
}

public class HogeSettings : ConfigurationSection
{
    [ConfigurationProperty(“providers”, Options = ConfigurationPropertyOptions.IsRequired)]
    public ProviderSettingsCollection Providers
    {
        get { return (ProviderSettingsCollection)this[“providers”]; }
    }
    // Settings properties goes here
}

Lazy の initializer をメソッドバインドして遅延初期化とかまぁ普通にやればこうなるかなぐらいの実装ですね。

実際には defaultProvider プロパティの追加とか、それを元に Provider プロパティを出してとかやるともうちょっと伸びます。

んで、一個実装するぐらいならなんてことはない話なんですが、5つも6つも実装するとなるとぶっちゃけてお約束コードが長くて鬱になるという類です。

Initialize のオーバーライド

プロバイダ作ったら大抵なんかしら初期化のオーバーライドが必要になります。

このオーバライドをすると configs として渡される NameValueCollection をグチグチといじる必要があります。

これがコードでやると結構うっとおしいのです。

_configParam=configs[“parameterName”]==null ? defaultValue : int.Parse( configs[“parameterName”] );

をべたべた並べてやると int.Parse が失敗すれば例外吹っ飛んでいき、ダメならエラーになってくれるし、設定しくってる奴が悪いといえばそうなんだけど、ちゃんと何の設定違ってるとか例外の詳細カスタムしようとすると try {} catch { throw … } で括ってを並べる事になります。

世の中データバインディングにアノテーションだろって言ってもまぁアレです。

Doc<Code> のプロバイダ実装インフラを流用する

https://kazuktnd.wordpress.com/docofcode/ でライセンスに明記されてる通りで、「それ以外のソースコードおよびバイナリは自由に実行、解析、改変、再配布、他の製品への流用等ができます。 」の「他の製品への流用等ができます。」の通りです。アセンブリ一個取りだして流用も許諾されていますので、好きにしてください。って事です。

bin に展開されている CustomProviderInfrastructure.dll を取り出し、参照設定します。

using CustomProviderInfrastructure; // NameValueCollection の Bind 拡張メソッドに必要

public class HogeProvider: CustomProviderBase<HogeProvider, HogeSettings >
{
    [InitializeParameterRequired]
    private int _timeout;

    public override void Initialize(string name, NameValueCollection config)
    {
        config.Bind( this, self=>self._timeout, int.Parse );
    }
}
[DefaultConfigurationSectionName(“hogeSettings”)]
public class HogeSettings : CustomProviderSettingsBase
{
}

InitializeParameterRequired で _timeout が修飾されていますので、この場合 timeout は省略できません。

config.Bind は式木のプロパティ名/フィールド名から取得する要素名を決定します。デフォルトで先頭の _ は削られ、結果は camelCaseName にされます。(先頭が大文字なら小文字になる)、フィールドないしパラメータに InitializeParameterName 属性でパラメータ名が指定されれば、その名前で NameValueCollection の要素を取りだします。

変換時に例外が出たりすると、ConfigurationErrorsException にパラメータ名等付いた例外を再送出するので、例外を綺麗にするとかの為にコードを特に足す必要はありません。

Bind には省略可能パラメータでデフォルト値が指定できますので、InitializeParameterRequiredAttribute を付けない場合にはデフォルト値も指定してください。

以上で前述のコードでの ProviderCollection の絡みや ConfigurationSection の派生もすべて済みます。

web.config には DefaultConfigurationSectionName で指定されるセクションを記述します。

<hogeSettings defaultProvider=”default” >
    <providers>
        <add name=”default” type=”HogeProvider, HogeProviderServices” />
    </providers>
</hogeSettings>

あと、web.config の configSections にセクションの記述が要りますがそんなもん当然すぎるので割愛。

まとめ

好きに使って良いよなアセンブリも入ってますので、遊んであげてください。

広告

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト / 変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト / 変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト / 変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト / 変更 )

%s と連携中

%d人のブロガーが「いいね」をつけました。