テーブルにデータを設定する
最初に、データベーステーブルにデータを設定するため、実装予定のプロパティごとにescProperties行を作成します。プロパティIDが0のプロパティ行は作成しないでください。プロパティ名ではワイルドカードはサポートされていません。プロパティ値は会社によって大きく異なりますが、ほとんどの機関が、LogFileLocation、DebugLevel、ErrorReportingWebServiceURLなどのプロパティラベルを採用しているようです。
次に、別々に構成するモジュールごとにescModulesテーブルに行を作成します。ModuleIDがゼロのワイルドカード行も作成する必要があります。個人的には、実行可能ファイルに対するモジュール行だけでなく、マシンで実行するすべてのアセンブリに対してモジュール行を作成することをお勧めします。こうすれば、システム上のソフトウェアの各部分ごとに固有の構成情報を追加することができます。
最後に、社内のサーバーごとおよびロケーションごとに、escServersテーブルとescLocationsテーブルに行を追加します。また、前述の理由から、これらの両方のテーブルにもワイルドカード行を追加します。
本稿のダウンロードサンプルには、escTestというサンプルクライアントアプリケーションが含まれています。このクライアントは、フレームワークのしくみを理解したり、新しいローカルおよびリモートのストレージフレームワークをテストしたりするときに役立ちます。また、このクライアントを使って、SQL Serverデータベースが正しく構成されているかを確認することもできます。
複数の値を取得し、その後も取得した値がローカルキャッシュから返されていることを確認したら、レジストリを開き、ローカルのプロパティ値を検査します。レジストリエディタを使って、HKEY_Local_Machine\Software\EnterpriseSoftwareConfigurationに移動します。プロパティ値の取得に使ったModuleIDごとに、サブキーを探します。各ModuleIDのサブキー下に、値を取得したプロパティラベルごとに別々のサブキーがあります。PropertyValueレジストリキーとValidUntilレジストリキーは、プロパティラベルのサブキー下に保管されています。図4に、レジストリに階層構造で保管されているModuleID 1003の"Log File Location"プロパティを示します。
モジュールIDに基づいてすべてのプロパティ値を保管するということは、すべてのモジュールで共有されるプロパティ値(escPropertyValuesテーブルではModuleIDが0のプロパティ値)は重複して保管されるということです。言い換えれば、同じプロパティ値を参照するモジュールでも、モジュールごとに独自のコピーが保管されるということです。長所がいくつもあることを考えれば、これは許される範囲の犠牲です。ストレージを実装する方法が非常にシンプルであるだけでなく、このストレージスキームを採用すると、プロパティ値のストレージをデバッグするプロセスも簡素化されます。ModuleID 0に値を割り当てても、プロパティ値のすべてのインスタンスが同じになるわけではないということを思い出してください。このモデルでは、ModuleID 0に対する汎用プロパティ値を設定できる一方で、特定のモジュールについては同じプロパティに具体的な値を割り当てることができます。
また、ローカルキャッシュストレージにレジストリを使うという方法は、Windowsプラットフォームでしか使用できないことにも注意しましょう。他のプラットフォームには別のローカルストレージソリューションが必要です。
社内にプロジェクトを実装する
この構成システムがどの組織でも柔軟に機能することを示すために、サンプルプロジェクトの機能とソースコードはあえてシンプルにしておきました。プロジェクトを実装する前に、このプロジェクトがどのような目的に適したものかを確認しておきましょう。このフレームワークは、使用頻度の高いアプリケーションデータのキャッシュを目的としたものではありません。つまり、汎用的なキャッシュとは考えないでください。
このフレームワークの構築に使用した技法の多くは、このようなキャッシュ設計から取り入れていますが、大容量での使用のために、つまりもっと多くのデータを保管するためには、ローカルストレージクライアントとリモートストレージクライアントの設計を別に最適化する必要があります。すでに説明したように、このシステムは、レジストリや.NETのapp.configファイルを介してソフトウェア構成を管理する単に1つの選択肢にすぎません。
また、実際にプロジェクトを配備する前に、次のリストに挙げた修正の少なくとも一部を適用することを検討してください。
- 構成をもっと簡単にする、エンドユーザ向けの基礎的なWebベースの構成ツールを作成しておくと便利です。このツールは、プロパティ値の割り当てでワイルドカードの使用をサポートしていなければなりません。
- SQL Serverを使わない場合は、中央の構成リポジトリ固有のRemoteStorageClientクラスを追加してください。Oracle、レジストリ、LDAPのどれを使用するかに関係なく、コードを変更するプロセスは簡単で、本稿で説明したクライアントリポジトリの変更と同じです。
- 社内で、Windows 2000、Windows 2003、Linuxなど、複数の異なるプラットフォームを採用している場合は、escPlatformsテーブルの追加と、escPropertyValuesテーブルへのPlatform列の追加を検討しましょう。プラットフォームごとに具体的なプロパティ値をサポートできるようになります。これを行う場合は、escServersとescLocations間のリンクと同じ方法でescServersテーブルを新しいescPlatformsテーブルにリンクすることを忘れないでください。
- 1つのロケーションから稼動している場合は、escLocationsテーブルのサポートを省いてクエリと構成を簡素化することを検討しましょう。
- ローカルのキャッシュ内にあるプロパティ値の保管にレジストリを使いたくない場合は、LocalStorageClientを追加して他のローカルストレージメカニズムをサポートすることを検討しましょう。
- LocalStorageClientの複数のタイプのサポートを追加することを検討しましょう。前に説明したように、マシン上のアプリケーションの大半がASP.NETアプリケーションの場合は、ローカルストレージにASP.NETの組み込みキャッシュ機能を使ってみるとよいかもしれません。適切に構成されていれば、LocalStorageClientの基本クラスファクトリメソッド(GetLocalStorageClient)を変更して、クライアントアプリケーションのIDに応じて異なるLocalStorageClientの実装を返すことができます。完全にインメモリのローカルキャッシュの使用は、アプリケーションを停止して再始動した場合は機能しません。このような場合、キャッシュ内の値は失われるので、ローカルに再配布する必要があります。
- アプリケーションがどう構成されているかに応じて、escPropertyValuesテーブルまたはescPropertiesテーブル、あるいはその両方に属性を追加して「クリティカル(critical)」なプロパティをサポートすることを検討しましょう。サンプルプロジェクトでコーディングされているように、ValidFor期間を過ぎてもリフレッシュできないプロパティに対するLocalStorageClientの通常の動作は、有効期限切れのプロパティ値を返すことです。ただし、これは、"critical"と指定されたプロパティが有効期限切れの場合に、プロパティを中央のリポジトリから取得できないときはnull値を返すように変更することができます。
- 社内の標準エラーレポートフレームワークを使って、リポジトリから値を取得しようとしたときにエラーをログに記録するサポートを追加しましょう。プロジェクトをシンプルにするため、エラーレポート機能はサンプルプロジェクトには実装しませんでした。
- モジュールには汎用の構成値を割り当てるという考えに縛られないようにしましょう。ほとんどのモジュールはソフトウェアの物理的な部分を表していますが、モジュールのインスタンスを表すこともあります。たとえば、同じまたは類似するアセンブリの複数のインスタンスをロードするサービスがある場合、そのサービスの構成で、ロードする具体的なモジュールが指定されることがあります。サービスがロードする各モジュールは、それぞれ固有の構成設定を読み取ります。この概念を拡張することで、このシステムを使ってエンタープライズシステムを構成する方法の幅が著しく広がります。
- ローカルのWindowsサービスを実装すると、有効期限切れになる前にプロパティ値をプリフェッチすることができます。有効期限切れになる前にプロパティ値を取得しておけば、クライアントアプリケーションでローカルのプロパティ値をリフレッシュする際の遅延がほとんどなくなります。
- 前述のWindowsサービスの使用は、ローカルストレージで1カ月以上前のプロパティ値を調べて削除する場合にも役立つでしょう。これらの値を使う機会はおそらくもうないので、システムから削除する必要があります。
- プロパティ値をローカルにキャッシュする場合の1つの問題は、中央のリポジトリにある値のマスタコピーが変更されるとローカル内の値が古くなってしまうことです。たとえば、ValidForプロパティが1時間に設定されている場合、最もずれが大きいケースでは、サーバーが1時間前の値で実行されていることになります。したがって、ローカルサービスのもう1つの使い方として、プロパティ値を直ちに更新する必要がある場合は通知を受け取る、という機能が考えられます。このようなサービスがあれば、中央の新しい値をすべてのクライアントシステムにプッシュするために必要な時間を数秒に短縮することができます。
- サンプルプロジェクトの実装の1つの欠点は、中央のデータベースにアクセスできない場合に、有効期限切れのプロパティ値を取得しようとしてもすべてブロックされて、データベース接続がタイムアウトになるまで待たなければならないことです。ローカルストレージクライアントからの応答を取得するためには、データベースが応答不能であることがわかったときにそのデータベースへの不要な接続を防ぐフラグをローカルキャッシュに実装する必要があります。たとえば、レジストリ版のローカルストレージクライアントでは、EnterpriseSoftwareConfigurationサブキーのルートにフラグを追加して、中央のデータベースが応答不能であることと、システムが接続を再試行する間隔を示すことができます。このスキームでは、リモートストレージから読み取ろうとすると必ずnullが返されるため、プロパティ要求に対しては、ローカルキャッシュに保管されているバージョンが返されます。中央のデータベースへのアクセスはフラグによって制限します。たとえば、フラグを1分に設定した場合は、データベースがオフラインのときは1分間に1つのクライアントしかデータベースへのアクセスを試みません。クライアントが中央への接続に成功してプロパティを取得したら、フラグはクリアされ、通常のプロパティリフレッシュが再開します。
企業が成長すると、複数のサーバー上でソフトウェア構成プロパティを同期させておくことは困難になります。このサンプルコードで実現したプロジェクトをベースにして、各自のニーズに合わせて拡張し、独自のエンタープライズ対応ソフトウェア構成フレームワークを構築してみてはいかがでしょうか。

