原文「Modular Application Development Using Prism Library for WPF」
モジュール・アプリケーションは、より大規模なアプリケーションに統合することができる(modulesという名前の)対となる疎く結合した機能単位に分割されているアプリケーションです。クライアント・モジュールは、一部のアプリケーションの全体的な機能をカプセル化して、一般的な対となる関連する関係を表します。それは、ユーザー・インターフェイスとビジネス・ロジックやアプリケーション基盤構造の一部が含まれているアプリケーション機能のような、ログを記録するためのアプリケーション・レベルのサービスや認証しているユーザーのような、関連したコンポーネントのコレクションを含むことができます。モジュールは、相互に独立していますが、疎く結合したやり方で、互いに情報交換することができます。モジュール・アプリケーション設計を使用することで、あなたのアプリケーションを開発して、テストして、配布して、保持することをあなたのためのより簡単に作成します。
例えば、個人的な銀行業務アプリケーションを考えてみます。口座の間で、お金を送金する、請求を払う、1つのユーザー・インターフェイス(UI)から個人情報を更新するように、ユーザーは、いろいろな機能にアクセスすることができます。しかしながら、背後で、これらの機能の各々は、別々のモジュールの中でカプセル化されています。これらのモジュールは、互いに、そして、データベースサーバとWebサービスのような、バックエンドシステムと情報交換します。アプリケーションサービスは、それぞれの異なるモジュールの中に、様々なコンポーネントを統合し、そして、ユーザーとの通信を処理します。ユーザーは、一つのアプリケーションのように見える、統合ビューを見ています。
次の図は、複数のモジュールとモジュール・アプリケーションのデザインを示しています。
すべてのビジュアル・コンポーネントを格納します。
モジュールとシェルの間に、接着剤を提供します。
アプリケーションに、View、サービスと他の機能を提供します。
モジュール・アプリケーションを構築する利点
Benefits of Building Modular Applications
あなたは、おそらく、これまでに、アセンブリ、インターフェースとクラス、そして、優れたオブジェクト指向設計の原則を使用して、上手に設計されたアプリケーションを構築しています。それにしても、細心の注意が取られない限り、あなたのアプリケーション設計は、まだ「モノリシックである」場合があります。(すべての機能は、アプリケーション内のどこかで密接に結びついた方法で実装されています)、それは、アプリケーションを難しく開発、テスト、拡張、保守するために、作成することができます。
一方で、モジュール・アプリケーションの方法は、あなたのアプリケーションの大規模な機能領域を識別することで、あなたを助けることができます。そして、あなたが、独立してその機能を開発し、そして、テストすることができます。これは、より簡単に、開発とテストを作成することができますが、また、それは、あなたのアプリケーションを、将来、より柔軟に、そして、より簡単に拡張するために、作成することができます。 モジュール化による方法の利点は、あなたのアプリケーションを、扱いやすい断片に分割することができるため、あなたの全体的なアプリケーション・アーキテクチャを、より柔軟で保守しやすく作成できることです。それぞれの断片は、特定の機能をカプセル化します。そして、 各々の断片は、明白なものを通して、統合しますが、通信経路を疎く結合します。
モジュール・アプリケーション開発のためのPrismのサポート
Prism's Support for Modular Application Development
Prismは、あなたのアプリケーションの、モジュール・アプリケーション開発のためのサポートと実行時の管理モジュールを提供します。 Prismのモジュール開発機能を使用することで、あなたが、あなた独自のモジュラー性フレームワークの実装とテストをする必要がないため、あなたの時間を節約することができます。Prismは、次のモジュール・アプリケーションの開発機能をサポートしています。:
- 登録のためのモジュール・カタログは、モジュールとそれぞれのモジュールの場所に名をつけます。;あなたは、次に示す方法で、モジュール・カタログを作成することができます。:
- コードやExtensible Application Markup Language (XAML)でモジュールを定義することで、
- ディレクトリでモジュールを発見することによって、それで、あなたは、明示的に定義することなく、統合されたカタログで、すべてのあなたのモジュールを読み込むことができます。
- 設定ファイルでモジュールを定義することによって、
- モジュールのための宣言型のメタデータの属性は、初期化モードと依存関係をサポートします。
- 依存性注入コンテナとの統合により、モジュール間の疎結合をサポートします
- モジュールを読み込むために:
- モジュールが読み込まれていることを確認するために、重複とサイクル検出が含まれている依存関係の管理は、正しい順序で、一度だけ、読み込まれ初期化されます。
- アプリケーションの起動時間を最小限にするモジュールのオンデマンドとバックグラウンド・ダウンロード;残りのモジュールは、バックグラウンドで、あるいは、それらが必要とされるとき、読み込まれ、初期化されることができます。
中核となる概念
Core Concepts
モジュールは、アプリケーションに、別々に、開発し、テストし、配布し、統合することができる方法で、パッケージ化された機能の論理コレクションとリソースです。パッケージは、1つ以上のアセンブリであることができます。それぞれのモジュールは、モジュールを初期化し、そして、アプリケーションに、その機能を統合するための役割を果たす中心となるクラスを持っています。クラスは、IModuleインターフェイスを実装しています。
備考: IModuleインターフェイスを実装するクラスの存在は、モジュールとして、パッケージを識別するのに十分です。
IModuleインターフェイスには、あなたが、それを実装できる範囲で、モジュールの機能を初期化して、アプリケーションに統合するために必要なロジックは何でも構わないInitializeという名前の一つのメソッドがあります。モジュールの目的に応じて、それは、複数の要素で構成されたユーザー・インターフェイスに、ビューを登録することができます。アプリケーションが利用できる追加のサービスを作成します。次のコードは、モジュールの最低限の実装を示しています。
public class MyModule : IModule
{
public void Initialize()
{
// Do something here.
}
}
モジュールの寿命
Module Lifetime
- モジュールの登録/発見。特定のアプリケーションのための実行時に読み込まれるモジュールは、Moduleカタログで定義されています。カタログには、読み込まれるモジュールに関する、読み込まれた場所と順序の情報が含まれています。
- 読み込まれるモジュール。モジュールが含まれるアセンブリは、メモリに読み込まれます。この段階は、いくつかの遠隔地またはローカル・ディレクトリから取得することをモジュールに要求するかもしれません。
- モジュールを初期化する。モジュールは、続いて、初期化されます。モジュール・クラスの作成されるインスタンス、そして、IModuleインタフェースを通じて、それらのInitializeメソッドを呼び出すことを示しています。
次に示す図は、モジュールを読み込んでいるプロセスを示しています。
モジュールのカタログ
Module Catalog
ModuleCatalogは、アプリケーションによって使用することができる、モジュールに関する情報を格納しています。カタログは、本質的には、ModuleInfoクラスのコレクションです。それぞれのモジュールは、モジュールの他の属性の間の名前、型と場所を記録する、ModuleInfoクラスで記述されています。ModuleCatalogをModuleInfoインスタンスに書き込むには、いくつかの代表的な方法があります。:
- コード内のモジュールを登録する
- XAML内のモジュールを登録する
- 設定ファイル内にモジュールを登録する
- ディスク上のローカル・ディレクトリでモジュールを発見する
あなたが、使用する必要がある、登録と発見の仕組みは、あなたのアプリケーションが必要とするものに依存しています。設定ファイルやXAMLファイルを使用することは、あなたのアプリケーションが、モジュールへの参照を必要をなくすことができます。ディレクトリを使用することは、ファイルでそれらを指定することなく、アプリケーションが、モジュールを発見することができます。
いつモジュールを読み込むか制御する
Controlling When to Load a Module
Prismアプリケーションは、「利用可能な時」と知られているように、あるいは、「オンデマンド」として知られているように、アプリケーションがそれらを必要とするとき、可能な限り早くモジュールを初期化することができます。モジュールをロードするために、以下のガイドラインを考えて見てください。:
- アプリケーションが実行される時、アプリケーションを実行するために必要なモジュールは、アプリケーションで読み込まれ、初期化されている必要があります。
- 機能が含まれているモジュールは、それらが利用可能になるとき、たいてい、代表的な使い方で使用されるアプリケーションは、バックグラウンドで読み込まれ、そして、初期化されていることができます。
- めったに使用されない機能が含まれるモジュール(あるいは、他のモジュールが必要に応じて依存するモジュールをサポートします)要求に応じて、読み込まれ、初期化することができます。
あなたが、あなたのモジュールを、ダウンロードし、初期化するために、どのように、設定するか判断するために、あなたのアプリケーション、一般的に使用される筋書き、アプリケーション起動時間とダウンロードの数とサイズを、どのように、分割しているか考えてみてください。
統合されたモジュールとアプリケーション
Integrate Modules with the Application
Prismは、あなたのアプリケーションを起動する次のクラスを提供します。:UnityBootstrapperやMefBootstrapper。これらのクラスは、モジュールを発見して、ロードするために、モジュール・マネージャを作成して、設定するために使用することができます。あなたは、数行のコードで、XAMLファイル、設定ファイルやディレクトリの場所で、指定されるモジュールを登録するために、設定メソッドを上書きすることができます。
残りのアプリケーションでモジュールを統合するために、モジュールInitializeメソッドを使用します。この変化する、あなた行う方法は、 あなたのアプリケーションとモジュールの内容の構造に依存します。以下は、あなたのアプリケーションに、あなたのモジュールを統合するために、一般的な行なう必要があることです。:
- アプリケーションのナビゲーション構造に、モジュールのビューを追加します。ビュー発見やビュー注入を使用して、複数の要素で構成されたUIのアプリケーションを構築するとき、これは、一般的です。
- アプリケーションレベルのイベントやサービスに登録します。
- アプリケーションの依存関係注入コンテナで共有サービスを登録します。
モジュール間の通信
Communicate Between Modules
モジュールは、相互に、弱い結合を持つ必要がありますが、モジュールが互いに、情報をやりとりすることは一般的です。各々それら独自の強さで、いくつかの疎く結合した通信パターンがあります。通常、これらのパターンの組合せは、結果として得られる解決法を作成するために使用されます。以下は、これらのパターンのいくつかを紹介します。:
- 疎く結合したイベント。モジュールは、確実にイベントが発生したことを、くまなく伝えることができます。他のモジュールは、イベントが発生するとき、それらが通知されるように、それらのイベントに登録することができます。疎く結合したイベントは、2つモジュールの間で通信を設定する軽量な方法です。;その結果、それらは、簡単に実装されます。しかしながら、あまりに大量のイベントに頼るデザインは、特に、多くのイベントが、単一タスクを成し遂げるために、互いに組織化されている必要がある場合、保守するのが難しくなります。その場合、共有サービスを検討したほうが良いかもしれません。
- 共有サービス。共有サービスは、一般的なインターフェースによってアクセスすることができるクラスです。通常、共有サービスは共用アセンブリに存在し、認証、ログの記録、や設定のような、システム全体のサービスを提供します。
- 共有されたリソース。あなたが、モジュールが互いに、直接、情報のやりとりしたくない場合、あなたは、また、データベースや対となるWebサービスのような、共用リソースを通じて、それらに、間接的に情報をやりとりしてもらうことができます。
依存関係注入とモジュール・アプリケーション
Dependency Injection and Modular Applications
Unityアプリケーション・ブロック(Unity)と拡張管理フレームワーク(MEF)などのコンテナは、あなたが、簡単に、疎く結合したやり方で、コンポーネントを構成することを助けるパワフルなデザインパターンの制御の反転(IoC)と依存関係注入を使用できます。それは、コンポーネントが、参照をハードコードすることに依存せず、他のコンポーネントの参照を取得することができます。それによって、望ましいコードの再利用と柔軟性の向上を促進します。依存関係注入は、疎く結合した、モジュール・アプリケーションを構築するとき、極めて役に立ちます。Prismは、アプリケーション内のコンポーネントを構成するために使用される、依存関係注入コンテナを選ばないように設計されています。コンテナは、ご自由にお選びください。そして、主にあなたのアプリケーションの要件と選択によってきまります。しかしながら、Microsoftから、考慮するための2つの主要な依存関係の注入フレームワークが、あるでしょうか?UnityとMEF。
パターンと実践Unityアプリケーション・ブロックは、依存関係注入コンテナの完全な機能を提供します。それは、プロパティに基づいて、そして、コンストラクタに基づいて、なたが、コンポーネントの間で透過的な注入動作と方針ができる注入と注入方針をサポートします。;また、それは、依存関係注入コンテナで一般的な、他の機能の格納をサポートします。
MEF(それは、.NET Framework 4.5の一部です)は、依存関係注入をサポートすることによって、拡張可能な.NETアプリケーションを構築するためのサポートを提供します。 - コンポーネントの構成に基づいて、モジュール・アプリケーション開発をサポートする他の機能を提供します。それは、アプリケーションが実行時に、コンポーネントを発見すること、そして、疎く結合した方法でアプリケーションにそれらのコンポーネントを統合することができます。MEFは、素晴らしい拡張性と構成のフレームワークです。それには、アセンブリと型の発見、型の依存関係ソリューション、依存関係注入といくつかの素晴らしいアセンブリ・ダウンロード機能が含まれています。次に示すものと同様に、Prismは、MEF機能を利用することをサポートしています。:
- XAMLとコード属性を通してのモジュール登録
- 設定ファイルとディレクトリ走査を通してのモジュール登録
- モジュールが、読み込まれるような、状態の追跡
- MEFを使用する際のモジュールのための、ユーザー定義した宣言型のメタデータ
UnityとMEF依存関係注入コンテナの両方は、Prismで継ぎ目なく動作します。
重要な決定事項
あなたが、行うと思われる最初の決定は、あなたが、モジュール・ソリューションを開発したいかには、関係ありません。先のセクションで説明された、モジュール・アプリケーションを構築することは、多くの利点がありますが、あなたが、これらの利点を獲得するために必要な時間と労力に関係があります。あなたが、モジュールの解決案を開発することに決める場合、考慮するいくつかのことがあります。:
- あなたが、使用するフレームワークを決定します。あなたは、Prism、MEFや他のフレームワークを使用する、あなた独自のモジュール型のフレームワークを作成することができます。
- あなたのソリューションを、どのように系統化するかを決定します。それぞれのモジュールの境界を定義するモジュラアーキテクチャの方法に含まれているアセンブリは、それぞれのモジュールの一部です。アプリケーションが、どのように配布されるか、制御を終了することと同じように、あるいは、プラグインや拡張可能なアーキテクチャをサポートしたい場合、あなたは、開発を容易にするために、モジュールを使用することに決めることができます。
- あなたのモジュールを、どのように分割するかを決定します。例えば、機能分野、プロバイダー・モジュール、開発チームと配布要件によって、モジュールは、要件に基づいて、それぞれに分割することができます。
- アプリケーションが、決定する中心となるサービスを、すべてのモジュールに提供するでしょう。1つの例は、中心となるサービスで、障害報告サービスや認証と認可サービスができるかもしれません。
- あなたが、Prismを使用している場合、モジュール・カタログで、モジュールを登録するために、あなたが使用する方法を決定します。WPFのために、あなたは、コード、XAML、設定ファイルや発見されているモジュール、ディスクのローカル・ディレクトリの中でモジュールを登録することができます。あなたのモジュールの情報のやり取りと依存関係についての戦略を決定します。モジュールは、互いに情報をやりとりする必要があるでしょう。そして、あなたは、モジュール間で依存関係を扱う必要があります。
- あなたの依存関係注入コンテナを決定します。通常、モジュラーシステムは、疎結合とダイナミックローディングとモジュールの作成を提供するために、依存関係の注入、コントロールの反転やサービス・ロケーターを必要とします。Prismは、UnityやMEFに基づくアプリケーションのために、Unity、MEFや他のコンテナ、そして、提供されるライブラリを使用して、選択を提供します。
- アプリケーションの起動時間を最小にする。アプリケーションの起動時間を最小限にするために、モジュールの要求とバックグラウンドのダウンロードについて考えます。
- 配布要件の決定。あなたは、あなたが、アプリケーションをどのように配布するか考える必要があります。
次の項目では、これらの決定のいくらかについて、内容を提供します。
あなたのApplicationをモジュールに分割する
Partition Your Application into Modules
あなたが、モジュール化の手法で、アプリケーションを開発するとき、あなたは、アプリケーションを、個別に開発、テスト、配布することができる、別々のクライアント・モジュールに構築します。それぞれのモジュールは、あなたのアプリケーションの全体的な機能の一部をカプセル化するでしょう。あなたが、作成する必要のある最初の設計上の決定の1つは、アプリケーションの機能をモジュールに、どのように、分割するか決定することです。
モジュールは、対となる関連する関係をカプセル化する必要があります。そして、対となる異なった責任を持ちます。モジュールは、アプリケーションの垂直の一部や水平サービス層を示すことができます。大規模なアプリケーションは、両方の型のモジュールを持っているでしょう。
垂直の一部のまわりで、モジュールとアプリケーションは、系統化されます。
水平層のまわりで、モジュールとアプリケーションは、系統化されます。
より大規模なアプリケーションは、モジュールを垂直の一部と水平層で系統化されるかもしれません。モジュールのいくつかの例には、次のものが含まれています。:
- モジュールは、株トレーダーのリファレンス実装(株トレーダーRI)のNewsモジュールのような、特定のアプリケーションの機能が含まれています。
- モジュールには、購買、請求書や総勘定元帳を発行することのような、対となる関連した使用事例のための、特定のサブシステムや機能が含まれています。
- モジュールには、ログの記録、貯蔵と認可サービスやWebサービスのような、基盤構造サービスが含まれています。
- モジュールには、他の内部システムに加えて、Siebel CRMとSAPのような、基幹業務(LOB)システムを呼び出すサービスが含まれています。
モジュールは、他のモジュールで、依存関係の最低限のまとまりを備えている必要があります。モジュールが、他のモジュールで依存関係を持っている場合、それは、具体的な型の代わりに、共用ライブラリで定義されるインターフェースを使用して、あるいは、EventAggregatorイベント型を通じて、他のモジュールと情報をやりとりするために、EventAggregatorを使用して、疎く結合している必要があります。
モジュール方式の目標は、このような方法で、機能と技術は追加され、除去されるように、柔軟で、保守しやすく、安定なまま、アプリケーションを分割することです。これを達成する最も良い方法は、モジュールが、可能な限り独立する、そして、可能な限り分離するように、うまく定義されたインターフェースを持ってる、あなたのアプリケーションを設計することです。
プロジェクトをモジュール化する比率を決定する
Determine Ratio of Projects to Modules
モジュールを作成して、パッケージ化するためのいくつかの方法があります。推薦される最も一般的な方法は、モジュールにつき、一つのアセンブリを作成することです。これは論理モジュールを分離しておくのを助け、厳密なカプセル化を促進します。あなたが、モジュールを配布する方法をパッケージ化することと同じように、また、それは、より簡単に、アセンブリについて話すための、モジュール境界として、作成します。 しかしながら、何も一つのアセンブリに複数のモジュールが含まれることを妨げません。そして、場合によっては、これは、あなたのソリューションで、プロジェクトの数を最小限にするのを好まれるかもしれません。大規模なアプリケーションのため、10-50のモジュールを持つことは、珍しくありません。それ自身のプロジェクトに、それぞれのモジュールを分離することは、ソリューションに、多くの複雑さを追加します。そして、Visual Studioの処理能力を低下させることができます。時には、あなたが、アセンブリ/Visual Studioプロジェクトことに、1つのモジュールにくっつける選択する場合、モジュールを分割する、あるいは、モジュールを設定し、それら独自のソリューションで管理することは、意味があります。
疎結合のために、依存関係注入を使用する
Use Dependency Injection for Loose Coupling
モジュールは、ホスト・アプリケーションで、あるいは、他のモジュールで、提供されるコンポーネントとサービスに依存するかもしれません。 Prismは、モジュール間で、それらが、正しい順序で、読み込まれて、初期化されるように、依存関係を登録する機能をサポートします。Prismは、また、アプリケーションに読み込まれるとき、モジュールの初期化をサポートしています。モジュールの初期化の間、モジュールは、それが必要とする追加されたコンポーネントと他のモジュールが利用できるように作成するために含まれているサービスに、参照を取り出し、そして、あるいは、どんなコンポーネントとサービスでも、登録することができます。
例えば、依存関係注入コンテナやファクトリー・サービスを使用して、モジュールは、直接、具体的な型のインスタンスを生成しているディレクトリの代わりに、外部インタフェースのインスタンスを取得するために、独立した仕組みを使用する必要があります。UnityやMEFのような依存関係注入コンテナは、自動的にインターフェースのインスタンスと型を取得するために、依存関係注入を通す必要がある型を提供します。Prismは、依存関係注入のモジュールを簡単にを使用するために、UnityとMEFを一緒に統合します。
次の図表は、コンポーネントとサービスに、参照を取得する、あるいは、登録するために必要なモジュールが読み込まれるとき、操作の代表的な流れを示しています。
この例では、OrdersModuleアセンブリは、OrdersRepositoryクラスを定義します(それは、他のビューとクラスと一緒に、命令機能を実装します)。CustomerModuleアセンブリは、一般的に、サービスによって公開されるインターフェースに基づいて、OrdersRepositoryに依存するCustomersViewModelクラスを定義します。アプリケーションの起動と起動するプロセスは、次に示す手順が含まれています。:
- ブートストラッパーは、モジュールの初期化行程を開始します。そして、モジュール・ローダーは、OrdersModuleを読み込み、そして、初期化します。
- OrdersModuleの初期化は、コンテナと一緒にOrdersRepositoryを登録します。
- モジュール・ローダーは、続いて、CustomersModuleを読み込みます。モジュールを読み込む順序は、モジュール・メタデータ内の依存関係で指定することができます。
- CustomersModuleは、コンテナを通して、それ解決することによって、CustomerViewModelのインスタンスを構築します。CustomerViewModelは、(通常、そのインターフェイスに基づいて)OrdersRepository上で依存関係を持っています。そして、コンストラクタやプロパティ注入を通して、それを示します。コンテナは、OrdersModuleによって登録される型で、View Modelの構築に基づいて、その依存関係を注入します。最終結果は、それらのクラスの間の密結合なしで、CustomerViewModelからOrderRepositoryへのインターフェース参照です。
備考: OrderRespository(IOrderRepository)を露出させるために使用するインターフェースは、別々の「共有サービス」アセンブリや「命令サービス」アセンブリに存在させることができます。それらのサービスを公開するために、サービス・インターフェースと要求される型だけが、含まれています。この方法では、強い依存関係が、CustomersModuleとOrdersModuleの間にありません。
両方のモジュールが、依存関係注入コンテナで、暗黙的な依存関係を持っていることに注意してください。この依存関係は、モジュール・ローダーで、モジュール構築の間に注入されます。
中心となる筋書き
Core Scenarios
あなたのアプリケーションで、モジュールで動作するとき、この項目は、あなたが遭遇する一般的な筋書きを説明します。 これらの筋書きは、モジュールが、すでに読み込まれていることを検出する時、モジュールを定義、モジュールの登録と発見、モジュールの読み込み、モジュールの初期化、モジュールの依存関係の指定、要求に応じたモジュールの読み込み、背後でのリモートモジュールをダウンロードと検出が含まれています。 あなたは、コードの中で、XAMLやアプリケーション設定ファイルで、あるいは、ローカル・ディレクトリを探査することで、モジュールを登録し、発見することができます。
モジュールの定義
Defining a Module
モジュールは、アプリケーションに、別々に、開発し、テストし、配布し、統合することができる方法で、パッケージ化された機能の論理コレクションとリソースです。それぞれのモジュールは、モジュールを初期化し、そして、アプリケーションに、その機能を統合するための役割を果たす中心となるクラスを持っています。ここに、示されるように、クラスは、IModuleインターフェイスを実装しています。:
public class MyModule : IModule
{
public void Initialize()
{
// Initialize module
}
}
あなたが、Initializeメソッドを実装する方法は、あなたのアプリケーションの要件に依存しています。モジュール・クラス型、初期化モードと、どんなモジュール依存関係でも、モジュール・カタログで定義されています。カタログのそれぞれのモジュールのために、モジュール・ローダーは、モジュール・クラスのインスタンスを作成し,、そして、その次に、Initializeメソッドを呼び出します。モジュールは、モジュール・カタログで指定された順番で処理されます。モジュールが、ダウンロードされ、利用でき、そして、依存関係が満足するとき、ランタイムの初期化順序に基づきます。
あなたのアプリケーションが使用している、モジュール・カタログの種類に応じて、モジュール依存関係は、モジュール・クラスそれ自身の宣言型の属性によって、あるいは、モジュール・カタログ・ファイルの範囲内で、どちらでも設定できます。次のセクションでは、より多くの内容を提供します。
モジュールを登録し、発見する
Registering and Discovering Modules
アプリケーションが読み込むことができるモジュールは、モジュール・カタログで定義されています。Prismのモジュール・ローダーは、それらを読み込む、そして、順番に読み込むとき、決定するために、モジュールが、アプリケーションに読み込まれ、利用できるモジュール・カタログを使用します。
モジュール・カタログは、IModuleCatalogインターフェースを実装するクラスによって表示されます。モジュール・カタログ・クラスは、アプリケーション初期化の間、アプリケーション・ブートストラッパー・クラスによって作成されます。Prismは、あなたが選択するモジュール・カタログの異なる実装を提供します。また、あなたは、AddModuleメソッドを呼び出すことによって、あるいは、カスタマイズされた動作で、モジュール・カタログを作成するために、ModuleCatalogから派生することで、他のデータ・ソースからモジュール・カタログを埋め込むことができます。
備考: 通常、Prismのモジュールは、モジュールの初期化のために必要な型のインスタンスを取り出すために、依存関係注入コンテナと一般的なサービス・ロケーターを使用しています。UnityとMEFコンテナは、Prismでサポートされています。モジュールを登録し、発見し、ダウンロードし、初期化する全体的なプロセスは、同じものですが、内容は、UnityやMEFが使用されているかどうかに基づいて、異なっています。方法の間のコンテナ固有の違いは、この項目を通して説明されます。
コード内のモジュールを登録する
Registering Modules in Code
ほとんどの基本的なモジュール・カタログは、ModuleCatalogクラスによって、提供されます。あなたは、モジュール・クラス型を指定することによって、プログラム上で、モジュールを登録するこのモジュール・カタログを使用することができます。また、あなたは、モジュール名と初期化モードを、プログラム上で指定することができます。ModuleCatalogクラスで、モジュール・ディレクトリを登録するために、あなたのアプリケーションのブートストラッパー・クラスで、AddModuleメソッドを呼び出します。例は、次のコードで示されます。
備考: あなたのアプリケーションが、モジュール型に、直接、参照をする場合、上で示されるように、あなたは、型で、それを追加することができます。;それ以外の場合には、あなたは、完全修飾型の名前とアセンブリの位置を提供する必要があります。
コードの中で、モジュール・カタログを定義するための他の例を参照するには、株トレーダーのリファレンス実装(株トレーダーRI)のStockTraderRIBootstrapper.csを参照してください。
備考: Bootstrapper基底クラスは、ModuleCatalogの作成を支援するために、CreateModuleCatalogメソッドを提供します。既定では、このメソッドは、ModuleCatalogインスタンスを作成します。しかし、このメソッドは、モジュール・カタログの異なる型を作成するために、派生クラスで上書きすることができます。
XAMLファイルを使用しているモジュールの登録
Registering Modules Using a XAML File
あなたは、XAMLファイルでそれを指定することによって、宣言的にモジュール・カタログを定義することができます。XAMLファイルが、どんな種類のモジュール・カタログ・クラスを作成するか、そして、どのモジュールを追加するか指定します。通常、.xamlファイルは、あなたのシェル・プロジェクトへのリソースとして追加されています。モジュール・カタログは、ブートストラッパーとCreateFromXamlメソッドの呼び出しで作成されます。技術的な観点から、XAMLファイルが、インスタンスを生成するオブジェクトの階層を簡単に定義するため、この方法は、コード内で、ModuleCatalogを定義することに、極めてよく似ています。
次のコードの例は、モジュール・カタログを指定しているXAMLファイルを示しています。
<--! ModulesCatalog.xaml -->
<Modularity:ModuleCatalog xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
xmlns:Modularity="clr-namespace:Microsoft.Practices.Prism.Modularity;assembly=Microsoft.Practices.Prism">
<Modularity:ModuleInfoGroup Ref="file://DirectoryModules/ModularityWithMef.Desktop.ModuleB.dll" InitializationMode="WhenAvailable">
<Modularity:ModuleInfo ModuleName="ModuleB" ModuleType="ModularityWithMef.Desktop.ModuleB, ModularityWithMef.Desktop.ModuleB, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
</Modularity:ModuleInfoGroup>
<Modularity:ModuleInfoGroup InitializationMode="OnDemand">
<Modularity:ModuleInfo Ref="file://ModularityWithMef.Desktop.ModuleE.dll" ModuleName="ModuleE" ModuleType="ModularityWithMef.Desktop.ModuleE, ModularityWithMef.Desktop.ModuleE, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<Modularity:ModuleInfo Ref="file://ModularityWithMef.Desktop.ModuleF.dll" ModuleName="ModuleF" ModuleType="ModularityWithMef.Desktop.ModuleF, ModularityWithMef.Desktop.ModuleF, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null">
<Modularity:ModuleInfo.DependsOn>
<sys:String>ModuleE</sys:String>
</Modularity:ModuleInfo.DependsOn>
</Modularity:ModuleInfo>
</Modularity:ModuleInfoGroup>
<!-- Module info without a group -->
<Modularity:ModuleInfo Ref="file://DirectoryModules/ModularityWithMef.Desktop.ModuleD.dll" ModuleName="ModuleD" ModuleType="ModularityWithMef.Desktop.ModuleD, ModularityWithMef.Desktop.ModuleD, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
</Modularity:ModuleCatalog>
備考: ModuleInfoGroupsは、同じアセンブリ内にあるモジュールをグループ化するための便利な方法を提供し、同じように初期化され、あるいは、同じグループ内のモジュールで、依存関係を持っているだけです。モジュール間の依存関係は、同じModuleInfoGroup内のモジュールの内で定義することができます。;しかしながら、あなたは、異なるModuleInfoGroups内のモジュールの間で、依存関係を定義することができません。モジュールをモジュール・グループに配置することは、選択可能です。グループのために設定されるプロパティは、そのすべてが含まれたモジュールに適用されるでしょう。また、モジュールが、グループ内になくても登録できることに注意します。
あなたのアプリケーションのブートストラッパー・クラスでは、次のコードで示すように、あなたは、XAMLファイルは、あなたのModuleCatalogのためのソースで、指定する必要があります。
設定ファイルを使用してモジュールを登録する
Registering Modules Using a Configuration File
WPFでは、App.configファイルで、モジュール情報を指定することができます。この方法の利点は、このファイルがアプリケーションにコンパイルされないということです。これは極めて簡単に、アプリケーションを再コンパイルせずに、実行時に、それをモジュールに追加し、除去できます。
次のコードの例は、モジュール・カタログを指定している設定ファイルを示しています。あなたが、自動的に、モジュールが読み込まれることを望む場合、startupLoaded="true"を設定します。
<!-- ModularityWithUnity.Desktop\\app.config -->
<xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="modules" type="Prism.Modularity.ModulesConfigurationSection, Prism.Wpf"/>
</configSections>
<modules>
<module assemblyFile="ModularityWithUnity.Desktop.ModuleE.dll" moduleType="ModularityWithUnity.Desktop.ModuleE, ModularityWithUnity.Desktop.ModuleE, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" moduleName="ModuleE" startupLoaded="false" />
<module assemblyFile="ModularityWithUnity.Desktop.ModuleF.dll" moduleType="ModularityWithUnity.Desktop.ModuleF, ModularityWithUnity.Desktop.ModuleF, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" moduleName="ModuleF" startupLoaded="false">
<dependencies>
<dependency moduleName="ModuleE"/>
</dependencies>
</module>
</modules>
</configuration>
備考: たとえ、あなたのアセンブリが、グローバル・アセンブリ・キャッシュに、あるいは、アプリケーションとして、同じフォルダの中にあるとしても、assemblyFile属性は必要です。属性は、適切なIModuleTypeLoaderにmoduleTypeを、マッピングするために使用されます。
あなたのアプリケーションのブートストラッパー・クラスでは、あなたは、設定ファイルが、あなたのModuleCatalogのためのソースであることを指定する必要があります。これを実行するには、あなたは、次のコードの示される、ConfigurationModuleCatalogクラスを使用します。
protected override IModuleCatalog CreateModuleCatalog()
{
return new ConfigurationModuleCatalog();
}
備考: あなたは、今まで通り、コードの中で、ConfigurationModuleCatalogにモジュールを追加することができます。あなたは、例えば、あなたのアプリケーションが、機能するために絶対に必要なカタログで定義されたモジュールを確認するために、これを使用することができます。
ディレクトリでモジュールを見つける
Discovering Modules in a Directory
PrismのDirectoryModuleCatalogクラスは、WPFのモジュール・カタログとして、あなたが、ローカル・ディレクトリを指定することができます。このモジュール・カタログは、あなたのアプリケーションのためのモジュールを定義する、指定されたフォルダを走査し、アセンブリを探します。この方法を使用するために、あなたは、モジュール名とそれらが持っているどんな依存関係でも指定するために、あなたのモジュール・クラス上で、宣言型の属性を使用する必要があるでしょう。次のコード例は、ディレクトリ内のアセンブリを発見することにより埋め込まれるモジュール・カタログを示します。
protected override IModuleCatalog CreateModuleCatalog()
{
return new DirectoryModuleCatalog() {ModulePath = @".\\Modules"};
}
モジュールを読み込む
Initializing Modules
モジュールが、読み込まれた後、それらは初期化されます。これは、モジュール・クラスのインスタンスが、作成され、そして、そのInitializeメソッドが、呼び出されることを示しています。初期化は、モジュールとアプリケーションを統合するための場所です。モジュールの初期化のための次の可能性を考慮してください。:
- アプリケーションで、モジュールのビューを登録します。あなたのモジュールが、ビュー発見やビュー注入を使用して、ユーザー・インターフェイス(UI)の構成に関与している場合、あなたのモジュールは、適切な領域名で、そのViewやView Modelを関連付ける必要があるでしょう。これは、アプリケーション内で、ビューを動的に、メニュー、ツールバーや他の視覚的な領域に表示することができます。
- アプリケーションレベルのイベントやサービスに登録します。多くの場合、アプリケーションは、あなたのモジュールが、興味があるアプリケーション固有のサービスそして、あるいは、イベントを公開します。それらのアプリケーション・レベルのイベントとサービスに、モジュールの機能を追加するために、Initializeメソッドを使用します。
例えば、アプリケーションは、シャットダウンしているとき、イベントを発生させるかもしれません。そして、あなたのモジュールは、そのイベントに反応したがっています。それは、あなたのモジュールが、アプリケーション層サービスに、いくつかのデータを提供する必要があることもできます。例えば、あなたが、(メニュー項目を追加し、削除する責任がある)MenuServiceを作成した場合、モジュールのInitializeメソッドは、あなたが、正しいメニュー項目を追加する場所です。
備考: モジュール・インスタンスの寿命は、規定では短命です。Initializeメソッドが、読み込みプロセスの間に呼び出されたあと、モジュール・インスタンスへの参照は、解放されます。あなたが、モジュール・インスタンスに、強い参照チェーンを確立ていない場合、それは、ガベージコレクトされるでしょう。単純に、ガーベジコレクタが実行されると、あなたのモジュールが「見えなく」なるため、あなたが、あなたのモジュールへ弱い参照を格納するイベントに登録する場合、この動作は、デバッグするために、問題になるかもしれません。
- 依存関係注入コンテナと型を登録します。あなたが、UnityやMEFのような、依存関係注入パターンを使用している場合、モジュールは、使用するためのアプリケーションや他のモジュールのために型を登録するかもしれません。また、それは、必要とする型のインスタンスを解決するために、コンテナを要求するかもしれません。
モジュールの依存関係を指定する
Specifying Module Dependencies
モジュールは、他のモジュールに依存するかもしれません。モジュールAが、モジュールBに依存する場合、モジュールBは、モジュールAの前に初期化する必要があります。ModuleManagerは、これらの依存関係を追跡し続け、それに対応してモジュールを初期化します。あなたが、コード、設定やXAMLで、あなたのモジュールの依存関係を定義することができる、モジュール・カタログを定義した方法に依存します。
コード内で、依存関係を指定する
Specifying Dependencies in Code
次のコードの例に示すように、モジュールをコードに登録するWPFアプリケーションやディレクトリで、モジュールを発見するために、Prismは、モジュールを作成するとき、使用する宣言型の属性を提供します。
// (when using Unity)
[Module(ModuleName = "ModuleA")\]
[ModuleDependency("ModuleD")\]
public class ModuleA: IModule
{
...
}
XAMLで依存関係を指定します
Specify Dependencies in XAML
次のXAMLは、Module FがModule Eに依存する場所を示します。
<-- ModulesCatalog.xaml -->
<Modularity:ModuleInfo Ref="file://ModularityWithMef.Desktop.ModuleE.dll" moduleName="ModuleE" moduleType="ModularityWithMef.Desktop.ModuleE, ModularityWithMef.Desktop.ModuleE, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null">
<Modularity:ModuleInfo Ref="file://ModularityWithMef.Desktop.ModuleF.dll" moduleName="ModuleF" moduleType="ModularityWithMef.Desktop.ModuleF, ModularityWithMef.Desktop.ModuleF, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null">
<Modularity:ModuleInfo.DependsOn>
<sys:String>ModuleE</sys:String>
</Modularity:ModuleInfo.DependsOn>
</Modularity:ModuleInfo>
. . .
設定で依存関係を指定します
Specify Dependencies in Configuration
次の例のApp.configファイルは、Module FがModule Eに依存する場所を示しています。
<!-- App.config -->
<modules>
<module assemblyFile="ModularityWithUnity.Desktop.ModuleE.dll" moduleType="ModularityWithUnity.Desktop.ModuleE, ModularityWithUnity.Desktop.ModuleE, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" moduleName="ModuleE" startupLoaded="false" />
<module assemblyFile="ModularityWithUnity.Desktop.ModuleF.dll" moduleType="ModularityWithUnity.Desktop.ModuleF, ModularityWithUnity.Desktop.ModuleF, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" moduleName="ModuleF" startupLoaded="false">
<dependencies>
<dependency moduleName="ModuleE" />
</dependencies>
</module>
</modules>
要求に応じてモジュールを読み込む
Loading Modules on Demand
要求されるモジュールを読み込むために、あなたは、InitializationModeをOnDemandに設定し、モジュール・カタログに読み込まれている必要があることを指定する必要があります。あなたが、それを実行したあと、あなたは、あなたのアプリケーションに、モジュールが読み込まれるという要望をコードを記述する必要があります。
コードの要求に応じて読み込みを指定する
Specifying On-Demand Loading in Code
次のコードの例に示すように、モジュールは、要求に応じて、属性を使用して指定されます。
// Boostrapper.cs
protected override void ConfigureModuleCatalog()
{
. . .
Type moduleCType = typeof(ModuleC);
this.ModuleCatalog.AddModule(new ModuleInfo()
{
ModuleName = moduleCType.Name,
ModuleType = moduleCType.AssemblyQualifiedName,
InitializationMode = InitializationMode.OnDemand
});
. . .
}
XAMLの要求に応じて読み込みを指定する
Specifying On-Demand Loading in XAML
次のコードの例に示すように、あなたが、XAML内の、あなたのモジュール・カタログを定義するとき、あなたは、InitializationMode.OnDemandを指定することができます。
<!-- ModulesCatalog.xaml -->
...
<module assemblyFile="ModularityWithUnity.Desktop.ModuleE.dll" moduleType="ModularityWithUnity.Desktop.ModuleE, ModularityWithUnity.Desktop.ModuleE, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" moduleName="ModuleE" startupLoaded="false" />
設定の要求に応じて読み込みを指定する
Specifying On-Demand Loading in Configuration
次のコードの例に示すように、あなたが、App.configファイル内の、あなたのモジュール・カタログを定義するとき、あなたは、InitializationMode.OnDemandを指定することができます。
モジュールの要求に応じて読み込みを要求する
Requesting On-Demand Loading of a Module
要求に応じて、モジュールが指定されたあと、アプリケーションは、続いて、読み込むために、モジュールを要求することができます。読み込みを開始ししたいコードは、ブートストラッパーで、コンテナに登録したIModuleManagerに参照を得る必要があります。
モジュールが読み込まれたとき検出する
Detecting When a Module Has Been Loaded
モジュールが読み込まれる、読み込みが失敗する時、ModuleManagerサービスは、追跡するために、アプリケーションのためのイベントを提供します。あなたは、IModuleManagerインターフェースの依存関係注入を通じて、このサービスへの参照を取得することができます。
this.moduleManager.LoadModuleCompleted += this.ModuleManager_LoadModuleCompleted;
void ModuleManager_LoadModuleCompleted(object sender, LoadModuleCompletedEventArgs e)
{
...
}
アプリケーションとモジュールを疎く結合し続けるために、アプリケーションは、アプリケーションでモジュールを統合するために、このイベントを使用することを避ける必要があります。その代わりに、モジュールのInitializeメソッドは、アプリケーションで統合する処理をする必要があります。
LoadModuleCompletedEventArgsには、IsErrorHandledプロパティが含まれています。モジュールが、読み込みに失敗した場合、そして、アプリケーションは、エラーを記録する、そして、このプロパティを、trueに設定することができる例外を投げることから、ModuleManagerを妨げることを望みます。
備考: モジュールが読み込まれて、初期化されたあと、モジュールアセンブリをアンロードできません。モジュール・インスタンスの参照は、モジュール・クラスインスタンスは、初期化が完了していたあと、ガーベージとして集められるため、Prismライブラリで、格納されていません。
MEFのモジュール
Modules in MEF
あなたが、依存関係注入コンテナとして、MEFを使用することを選択する場合、この項目は、違いだけを強調します。
備考: MEFを使用するとき、MefModuleManagerは、MefBootstrapperによって使用されます。新しい型が、MEFでインポートされるとき、ModuleCatalogが更新されることを確実とするために、ModuleManagerを拡張し、IPartImportsSatisfiedNotificationインターフェースを実装します。
MEFを使用して、コード内のモジュールを登録する
Registering Modules in Code Using MEF
MEFを使用するとき、あなたは、ModuleExport属性を、MEFに、自動的に型を発見させるために、モジュール・クラスに適用することができます。以下は一例です。
[ModuleExport(typeof(ModuleB), InitializationMode = InitializationMode.OnDemand)]
public class ModuleB : IModule
{
...
}
また、あなたは、アセンブリと複数のカタログを1つの論理的カタログに結合することができるAggregateCatalogクラスで、すべてのエクスポートされたモジュール・クラスを発見するために、使用することができる、AssemblyCatalogクラスを使用して、MEFを発見するために、モジュールを読み込むために、使用することができます。既定では、PrismのMefBootstrapperクラスは、AggregateCatalogインスタンスを作成します。次のコードの例に示すように、あなたは、続いて、アセンブリを登録するために、ConfigureAggregateCatalogメソッドを上書きすることができます。
PrismのMefModuleManagerの実装は、MEFのAggregateCatalogとPrismのModuleCatalogの同期を維持します。それによって、Prismは、ModuleCatalogやAggregateCatalogを通して、追加されるモジュールを発見することができます。
備考:
MEFは、Valueプロパティが使用されるまで、エクスポートされた、そして、インポートされた型のインスタンス生成を防ぐために、広範囲にわたり、Lazy
MEFを使用しているディレクトリでモジュールを発見する
MEFを使用しているディレクトリでモジュールを発見する
MEFは、モジュールが含まれているアセンブリ(そして、他のMEFは、型をエクスポートしました)のためのディレクトリを調べるために使用することができるDirectoryCatalogを提供します。この場合、あなたは、ディレクトリを登録するために、ConfigureAggregateCatalogメソッドを上書きします。このアプローチは、WPFでのみ、利用できます。
この方法を使用するために、あなたは、最初に、ModuleExport属性を使用している、あなたのモジュールに、モジュール名と依存関係を適用する必要があります。次のコードの例に示すように、これは、MEFが、モジュールをインポートできます。そして、Prismが、更新されたModuleCatalogを維持することができます。
// (when using MEF)
[ModuleExport(typeof(ModuleA), DependsOnModuleNames = new string[] { "ModuleD" })]
public class ModuleA : IModule
{
...
}
MEFは、実行時に、モジュールを発見することができるため、また、あなたは、実行時に、モジュールの間で新しい依存関係を発見するかもしれません。けれども、あなたは、ModuleCatalogと一緒に、MEFを使用することができます。ModuleCatalogが、(モジュールが読み込まれる前に)XAMLや設定から読み込まれるとき、依存関係チェーンを検証することを覚えておくことは重要です。モジュールが、ModuleCatalogで一覧にされる、そして、その次に、MEFを使って読み込まれる場合、ModuleCatalog依存関係は使用され、そして、DependsOnModuleNames属性は無視されるでしょう。
MEFを使用して、要求に応じて読み込みを指定する
Specifying On-Demand Loading Using MEF
あなたが、モジュールとモジュール依存関係を指定するための、MEFとModuleExport属性を使用している場合、ここに、示されるように、あなたは、指定するために、モジュールは、要請に応じて読み込まれる必要がある、InitializationModeプロパティを使用することができます。:
[ModuleExport(typeof(ModuleC), InitializationMode = InitializationMode.OnDemand)]
public class ModuleC : IModule
{
}
詳細情報
More Information
アセンブリ・キャッシュの詳細については、MSDNの上で「どのように:Assembly Library Cachingを使用するか」を確かめます。
Prismのモジュール方式の詳細については、WPFのクイックスタートのための、モジュラー性とMEF、あるいは、WPFのクイックスタートのための、モジュラー性とUnityを参照してください。クイックスタートの詳細については、以下を参照してください。:
Prismライブラリで拡張することができる、モジュラー機能に関する情報についていは、Prismを拡張する内の、Modulesを参照してください。