Web クライアントの設計と実装に関するガイドライン : プレゼンテーション層での設計パターンの使用

Patterns & Practices ホーム

Microsoft Corporation

November 2003

対象 :
   Microsoft .NET Framework
   ASP.NET

概要 : 一般的な設計パターンを使用して、プレゼンテーション層のコンポーネントの役割を分担する方法を説明します。この章では、主要な設計パターンの実装テンプレートを紹介します。テンプレートは、User Interface Process Application Block に含まれています。この章では、独自のユーザー インターフェイス コードの基礎としてこのブロックを使用する方法を説明しているので、コンポーネントの役割分担の利点を理解できます。

目次

この章の内容

設計パターンを使用する利点

プレゼンテーション層の設計パターンの使用

User Interface Process Application Block の使用による設計パターンの実装

まとめ

この章の内容

この章では、プレゼンテーション層の設計パターンを使用してユーザー インターフェイスの一般的な問題点を解決する方法を説明します。また、アプリケーションのユーザー インターフェイス プロセス コンポーネントを Microsoft User Interface Process Application Block を使用して実装する方法を説明します。この章には、以下のセクションが含まれています。

  • 設計パターンを使用する利点
  • プレゼンテーション層の設計パターンの使用
  • User Interface Process Application Block の使用による設計パターンの実装

この章では、プレゼンテーション層に設計パターンを適用する方法を説明します。設計パターンにより、プレゼンテーション層のコンポーネントが分解、編成され、実装コードの品質が向上します。さらに、コンポーネントの再利用により開発者の生産性が上がり、コードの管理の容易さの向上にも役立ちます。また、設計パターンは、状態管理、データ アクセス、非同期プログラミングやこのガイドの後半の章で説明しているその他の領域について決定を下す際に、影響を受けるコンポーネントを特定するのに役立ちます。

設計パターンを使用する利点

ビジネス アプリケーションで直面するコンピュータ処理の問題点の多くは、どこかで誰かが直面し、既に解決済みの問題点です。解決済みのソリューションに基づいた設計パターンと再利用のしくみは、大規模アプリケーションに存在する複雑さの克服に役立ちます。以下に、設計パターンと再利用可能なコンポーネントの利点を簡単に要約します。

  • 設計パターン - 設計パターンにより、一般的な問題点を解決するための証明済みの手法にアクセスでき、独自のアプリケーションの品質を向上するために、IT コミュニティの蓄積された知識や経験を使用できるようになります。パターンを使用して、証明済みの方法でコードを編成し、汎用的な問題点の解決に役立てることができます。

    プレゼンテーション層に関する問題点の解決に役立つ証明済みの設計パターンは数多く存在します。適切なパターンを選択することにより、関連性のないタスクや機能を分離する管理しやすいコードになります。このようなパターンの使用により、アプリケーションで適切なモジュール化が行われ、結束性が高くなり、結合性が低くなります。これらは、適切に設計されたシステムの本質的な特性でもあります。この章で説明している設計パターンは、Windows フォーム ベースのユーザー インターフェイスと ASP.NET Web ページの両方を対象にしています。

  • 再利用可能なコンポーネント - 再利用可能なコンポーネントは、多くのアプリケーションに共通する機能をカプセル化し、一連の設計パターンに従って独自のコンポーネントを構築する際の生産性を向上します。

    Microsoft User Interface Process Application Block は再利用可能なコンポーネントで、MVC (Model-View-Controller) パターンとApplication Controller パターンに基づくユーザー インターフェイスを構築する際に役立ちます。このブロックは、ユーザー インターフェイスに含まれている関連ページや関連フォーム間のナビゲーションを簡潔にします。また、アプリケーションの現在状態のスナップショットを取ることができるので、ユーザーは後から同じ状態でアプリケーションを再開できます。さらに、ユーザーとの対話処理やユーザー インターフェイスの表示を行うコードと、補助的なタスクを実行するコードを明確に分離できます。このアプローチにより、同一のプログラミング モデルを Windows フォーム アプリケーション、Web フォーム アプリケーション、およびモバイル アプリケーションに使用できます。

次のセクションでは、プレゼンテーション層の設計パターンの使用方法を説明します。再利用可能なコンポーネントは、この章の後半で説明します。

プレゼンテーション層の設計パターンの使用

プレゼンテーション層から、十分にドキュメント化され、十分に理解された設計パターンが数多く作成されます。設計パターンの目的を以下に示します。

  • 機能する単純なメカニズムをドキュメント化すること
  • 共通の語彙と分類を開発者や設計者に提供すること
  • ソリューションをパターンの組み合わせとして簡潔に表現できるようにすること
  • アーキテクチャ、設計、および実装に関する決定を再利用できるようにすること

パターンを適切に使用することで、アプリケーションのビルドにかかる設計作業と開発作業が軽減されます。さらに、広く使用されているパターンを採用することにより、管理の容易性を向上し、前半の設計上の決定が開発過程や実稼動のライフサイクルの後半に大きく影響するというリスクを軽減します。

プレゼンテーション層の設計が適切に行われなかった場合は、問題の解決に非常に多くの費用と時間が必要になります。設計上の決定が適切ではなかったことに気付くのは、通常、以下のような場合です。

  • ユーザー インターフェイスのフォームやページ間の重要な関係を必要とする、複雑性を増すユーザー操作をサポートする必要がある場合。
  • 既存のビジネス プロセスが変化したために、新機能や変更した機能をユーザーに提供する必要がある場合。
  • アプリケーションを他のプラットフォームに移植する必要がある場合、またはアプリケーションを (モバイル デバイスなどの) 別の種類のクライアントでもアクセスできるようにする必要がある場合。

頻繁に使用されるパターンに基づいて設計することにより、このようなシナリオに関連する多くの問題点を回避できます。以下のセクションでは、プレゼンテーション層に適用できるパターンを説明し、各設計パターンを使用するときの推奨事項を示します。

設計パターンの選択

以下のガイダンスを使用して、対象とするプレゼンテーション層に適した設計パターンを選択し、使用するのに役立てます。

  • パターンについての以下の説明を読み、図 2.1 を参考にして各設計パターンを使用する根拠を理解します。
  • 特定の要件に対処するパターンを特定し、そのパターンの設計レベルと実装レベルの説明を調べます。
  • 要件に関連するパターンの実装サンプルを調査します。パターンごとに実装サンプルを利用できます。実装サンプルは、.NET Framework アプリケーションへのパターンの適用方法を示します。
  • User Interface Process Application Block の使用が設計パターンの実装に役立つかどうかを評価します。詳細については、この章の後半の「User Interface Process Application Block の使用によるデザイン パターンの実装」を参照してください。

常に、簡単に、適切なパターンを使用できるとは限りません。パターンが提供するのは、多種多様な問題点に適用できる汎用的なソリューションです。特に、パターンの説明が非常に抽象的であったり、システム要件のドキュメントが不十分なものであった場合、どこにパターンを適用するのかを理解するのが困難になる可能性があります。

最終的に、特定のアプリケーション シナリオや環境で、開発チームに最も適したパターンを特定するのに役立てるために、実際的な経験をすることになります。リスクを軽減するために、できる限り多くのパターンを読み、実際のプロジェクトで使用する前に、テスト シナリオでパターンを実装してみることをお勧めします。

頻繁に使用されるプレゼンテーション層のパターン

MSDN のガイド「Enterprise Solution Patterns: Using Microsoft .NET」 (英語) では、.NET Framework アプリケーションのアーキテクチャ、設計、および実装にパターンを使用する方法が説明されています。このガイドの第 3 章では、プレゼンテーション層のパターンに注目し、プレゼンテーション層の設計に頻繁に使用されるパターンが説明されています。

プレゼンテーション層に最も関連のあるパターンとして以下のパターンが挙げられます。

  • Observer
  • Page Controller
  • Front Controller
  • Model-View-Controller (MVC)
  • Application Controller

Web アプリケーションとリッチ クライアント アプリケーションの間には、アプリケーションの種類ごとの設計パターンの関連度と適合度に影響する重要な違いがいくつかあります。以下のセクションでは、このような違いの概要と、このような違いが Web アプリケーションとリッチ クライアント アプリケーションの設計パターンの選択に与える影響について説明します。

Web アプリケーションのパターンとリッチ クライアント アプリケーションのパターンの違い

開発者に公開されるプログラミング モデルと状態管理方法の違いにより、Web プレゼンテーションに関連するパターンの一部には、クライアント アプリケーションのコンテキストにはあまり関連性がないと思えるものがあります。以下に例を示します。

  • Web アプリケーションはユーザーからのコマンドを表す HTTP 要求を受け取ります。Front Controller パターンなど、上記のパターンの一部には、このようなコマンドを大まかに指示、解釈、および実行する方法を記述したものがあります。

    ASP.NET では、HTTP 要求をページ コンポーネントのイベントや関数に割り当てるための基本的なパターンを使用します。また、このようなパターンを実装することもできます。

    状態を持たない HTTP の性質と Web アプリケーションが多くのユーザーに共有されるという事実は、要求と要求の間で、どこで、どのように状態を管理するのかを考える必要があることを意味します。 Application Controller パターンでは Web アプリケーションで状態管理を行う方法が記述されています。

  • リッチ クライアント アプリケーションは、一般的に、Windows オペレーティング システムに組み込まれるメッセージ ポンプなど、インメモリ メッセージ ポンプに基づくプラットフォーム上に構築されます。メッセージは、一般的に、ボタンのクリックやキーボードの入力など、低レベルのユーザー操作を表し、Web 要求よりもはるかに詳細になります。

    .NET Windows フォームは基礎となるメッセージ処理メカニズムをカプセル化し、Windows メッセージをフォーム コンポーネントの "イベント" に割り当てます。また、ビジネス アプリケーションでメッセージをインターセプトし、インターセプトしたメッセージを "ビジネス要求" として扱うこともできます。ただし、このアプローチは一般的ではないのでお勧めしません。

    リッチ クライアント アプリケーションには本質的に状態があり、一般的に 1 人のユーザーと対話します。これら 2 つの要因により、設計者や開発者が誤って状態管理を追加的なものと考えてしまうことがよくあります。このような考え方が、フォームとユーザー間での情報の共有を難しくします。上記の設計パターンは、リッチ クライアント アプリケーションで状態を共有する効果的なメカニズムを規定します。

パターンを選択する要因

この章の前半で挙げた各パターンには、固有の長所と特定のシナリオでの検討事項があります。

パターンの選択では、プレゼンテーション層のさまざまなクラスやコンポーネント間で役割を分担する方法を特定することが最も重要な要因になります。アプリケーション、チーム、環境にとって過度に複雑なパターンを使用すると、複雑性が増し、生産性が低下するリスクを伴います。

図 2.1 のパターンの説明を調べ、アプリケーションに適したパターンと必要な作業を判断します。

図 2.1. .NET Framework アプリケーションのプレゼンテーション層のパターンの選択

以下のセクションでは、図 2.1 で示した各パターンを説明します。各パターンの情報は以下のようにまとめてあります。

  • 問題点 - パターンが解決する問題点の種類を簡単に説明します。
  • ソリューション - 示された問題点をパターンがどのように解決するかを説明します。
  • パターンの使用時期 - 一般的にパターンを適用できる特定のシナリオです。
  • クラス図 - パターンに関連するクラスとインターフェイスを示す統一モデリング言語 (UML) クラス図です。
  • パターンの使用方法 - パターンの使用方法を順を追って説明したガイダンスです。
  • 関連情報 - 詳細情報とサンプルへのリンクです。

この情報は、特定のシナリオで、いつ、どのように適切な設計パターンを適用するかを決定する際に役立ちます。

Observer パターンの使用

Observer パターンにより、あるオブジェクトが他のオブジェクトに依存しないで、そのような他のオブジェクトに状態変化を通知するメカニズムが提供されます。

問題点 : マウス クリックやキーボード入力などのユーザー操作に反応する単純なシナリオがあります。このような操作に応じて、アプリケーションでロジックが実行されます。

ソリューション : ASP.NET コード ビハインド クラスまたは Windows フォーム イベントを使用して、ユーザー操作や入力に反応し、それに応じてデータを処理します。

パターンの使用時期 : ユーザーの操作と操作の間で状態を共有せず、ユース ケースにより複数のページやフォームにまたがって制御が流れないような、簡単なユーザー インターフェイスの場合に、Observer パターンを使用します。

クラス図 : 図 2.2 に Observer パターンに関係するクラスとインターフェイスを示します。

図 2.2. Observer パターン

Observer パターンを使用してユーザー インターフェイス コンポーネントからイベントを受け取る方法

  1. アプリケーションで応答する必要のあるユーザー操作または UI イベントを決定します。
  2. ASP.NET ページまたは Windows フォーム コントロールが提供するイベント ハンドラを使用するか (Microsoft Visual Studio® .NET 開発システムでは、通常、コントロールをダブルクリックすることでイベント ハンドラを得られます)、独自のハンドラを追加するかを判断します 。

以下に、.NET Framework プレゼンテーション層のコードで Observer パターンを実装する際の推奨事項を示します。

  • Visual Studio .NET サポートを使用し、できる限り多くの既定ハンドラを使用します。たとえば、Microsoft Visual C#® 開発ツール プロジェクトでイベント ハンドラを定義するには、Visual Studio .NET の [プロパティ] ウィンドウで、[イベント] の一覧を使用します。 Microsoft Visual Basic® .NET 開発システムプロジェクトでイベント ハンドラを定義するには、コード エディタ ウィンドウ上部の [クラス名] リスト ボックスと [メソッド名] リスト ボックスを使用します。
  • イベント ハンドラ メソッド名と、独自に定義したカスタム デリゲートやカスタム イベントに対して .NET Framework の標準名前付け規則を使用します。
  • イベント ハンドラを他のイベント ハンドラ メソッドから呼び出しません。 このような呼び出しにより、何が何のきっかけになっているのかが不明確なわかりにくいコードになります。
  • 特定のイベントの既定のイベント ハンドラを別のコントロールや別の操作のイベントにリンクしません。独自のイベント ハンドラを使用して、リンクの集約を明確にします。たとえば、Label コントロールの Click イベントと DoubleClick イベントの両方の処理に、同一のイベント ハンドラ メソッドを使用しません。
  • Visual C# のコードでは、+= 構文を使用してイベント ハンドラを登録します。Visual Basic .NET では、イベント ハンドラ メソッド シグニチャの最後に Handles controlname.EventName 構文を使用します。

関連情報

Page Controller パターンの使用

Page Controller パターンは MVC (Model-View-Controller) パターンの変形です (MVC については後半で説明します)。Page Controller パターンは、特に、ビューとコントローラが分離されているシンクライアント アプリケーションに適しています。このようなアプリケーションでは、表示はクライアントのブラウザで行われますが、コントローラはサーバー側アプリケーションの一部になります。

問題点 : ビジネス層を Web アプリケーションのプレゼンテーション ロジックから切り離したいと考えています。 また、各 Web ページのコントローラ コンポーネントのコードが重複しないで、柔軟かつ再利用可能な方法でコントローラ コンポーネントを構造化しようと考えています。

ソリューション : Page Controller コンポーネントを使用してページ要求から入力を受け取り、モデルで必要な操作を呼び出し、操作結果のページに使用する適切なビューを決定します。Page Controller により、ビュー関連のコードとディスパッチ ロジックとを分離できます。

Visual Studio .NET を使用して ASP.NET Web アプリケーションを作成すると、Web ページごとに自動的に Page Controller コンポーネントが用意されます。

パターンの使用時期 : 簡単なユーザー インターフェイスとページ間のナビゲーション パスを備えた Web アプリケーションで Page Controller パターンを使用します。 このようなシナリオでは、Page Controller コンポーネントのロジックが単純になるので、ナビゲーション コントロールを集中管理したり、ユーザー インターフェイス コンポーネント間で状態を共有する必要がありません。

クラス図 : 図 2.3 に、Page Controller パターンに関係するクラスを示します。

図 2.3. Page Controller パターン

プレゼンテーション層で Page Controller パターンを使用する方法

  1. 必要なコントローラ コンポーネントを特定します。このパターンは、多くの場合、コントローラ コンポーネントと Web ページを 1 対 1 でマッピングする場合に役立ちます。そのため、一般的に、ページごとに 1 つのコントローラが存在することになります。各 Web ページは特定のコントローラによって処理されるので、コントローラは限定された範囲内のみを処理する必要があり、簡潔さを保つことができます。

  2. コントローラ コードをそのページの ASP.NET コード ビハインドのクラスに記述するか、独立したクラスに記述するかを判断します。別のクラスを使用する場合の欠点は、HttpContext.Current プロパティを使用して ASP.NET コンテキスト情報にアクセスする必要が出てくる点です。HttpContext.Current プロパティは、現在の HTTP 要求について、HTTP 固有の情報をすべてカプセル化する HttpContext オブジェクトを返します。

    // 現在の HTTP 要求について、HTTP 固有の情報を取得します。
    HttpContext context = HttpContext.Current;
    
    

以下に、ASP.NET アプリケーションで Page Controller パターンを実装する際の推奨事項を示します。

  • 既定では、ASP.NET によりアプリケーションの Page Controller パターンが実装されます。Visual Studio .NET で作成される各ページは、自動的にコントローラ クラスを受け取ります。これは、ASPX ファイルの @ Page タグで指定されます。

    <%@ Page language="c#" 
             Codebehind="SimplePage.aspx.cs" 
             AutoEventWireup="false" 
             Inherits="SimplePage" %>
    
    

ユーザーが ASP.NET Web ページの URL へ移動するときに、Web サーバーによりそのリンクに関連付けられた URL が解析され、関連する ASP.NET ページが実行されます。事実上、ASP.NET ページはユーザーが行う操作のコントローラになります。また、ASP.NET ページにより、コントローラ コードを実行するための、コード ビハインド クラスも提供されます。コード ビハインド クラスにより、コントローラとビューが適切に分離され、さらに、すべてのコントローラに共通する機能を組み込むコントローラ基本クラスを作成できます。

  • 複数のページでのコントローラの共有については、このガイドの第 3 章「ASP.NET で管理しやすい Web インターフェイスをビルドする」を参照してください。

関連情報

Front Controller パターンの使用

Front Controller パターンは Page Controller パターンの変形です。Page Controller パターンでは、個別のコントローラ クラスが各 Web ページに関連付けられます。 このパターンは、Web ページ間の移動が分かりやすい、単純な Web アプリケーションに適しています。 それに対して、Front Controller パターンは、ページ コントローラ クラスが複雑なロジックを備え、深い継承階層の一部である場合や、アプリケーションがページ間の移動を構成可能な規則に基いて動的に決定する場合に適しています。

問題点 : ユーザー操作と入力を、どこで、どのように処理するのかという点に一貫性を持たせる必要があります。また、データ取得やセキュリティ チェックなど、その他のタスクを複数の Web ページで一貫して行う必要があります。

Page Controller パターンを使用し、各コード ビハインド ページで同一コードを記述することによって、このような目標を実現できます。ただし、この方法ではコード ビハインド クラスのコードが重複するので、コードの保守が難しくなります。

もう 1 つの方法として、Page Controller パターンを使用して、各ページ間に共通する動作を行う基本クラスを作成できます。ただし、この方法では、アプリケーションのページ数が増えた場合に、複雑で柔軟性に欠ける継承階層になる可能性があります。

ソリューション : 1 つのコントローラ クラスに複数の要求チャネルを持たせます。 このコントローラ クラスは、共有ロジックを 1 か所にまとめ、コントロールを適切なビューに転送する方法を決定します。

パターンの使用時期 : 複数ページ間の動作を共有させる Web アプリケーションや、Web ページ間の制御の流れが重要になる Web アプリケーションで Front Controller パターンを使用します。

クラス図 : 図 2.4 に Front Controller パターンに関係するクラスとインターフェイスを示します。

図 2.4. Front Controller パターン

Web アプリケーションで Front Controller パターンを使用する方法

  1. 複数ページで同様の方式で処理するコマンドを特定します。分類方法として、データベースのデータの更新やビジネス コンポーネントの実行など、要求が呼び出す機能の働きの種類による分け方と、監視、監査、または承認など、完了する動作に関連するポリシーや状況による分け方があります。
  2. HTTP Post 要求または HTTP Get 要求を Web サーバーから受け取り、関連するパラメータを要求から取り出すハンドラ クラスを作成します。ハンドラ クラスはこれらのパラメータを使用して適切なコマンドを実行し、要求を処理します。ハンドラ クラスを実装する一般的な方法は、ASP.NET の HttpHandler を使用する方法です。これを実現する方法を示したコード例は、「関連情報」で提供しています。ハンドラには最大限の効率が求められるので、どうしても必要な場合にのみ外部リソースを使用します。また、ハンドラのパフォーマンス向上のために、外部リソースをすべてキャッシュすることも検討する必要があります。

以下に、ASP.NET ページで Front Controller パターンを実装する際の推奨事項を示します。

  • Front Controller パターンを使用して Web ページ間に同様の動作を設定します。ただし、パフォーマンスに問題が生じる可能性があるので、アプリケーション全体を 1 つのフロント コントローラ クラスで扱わないでください。
  • Front Controller パターンを使用してユーザー インターフェイスの要求を処理し、ユーザーにそのユーザー インターフェイスを表示する場合、リダイレクトによって URL を更新する必要がある場合があります。リダイレクトを行わない場合は、アプリケーション全体の URL が 1 つだけになり、ハイパーリンクが機能しなくなることがあります。
  • フロント コントローラが処理する各要求は実行時にオーバーヘッドが生じるので、Front Controller の実装のパフォーマンスを慎重にテストします。

関連情報

Model-View-Controller (MVC) パターンの使用

MVC (Model-View-Controller) パターンは、中間層を追加してユーザー インターフェイス ロジックとビジネス層とを分離します。

問題点 : ビジネス層とプレゼンテーション ロジックとを分離する必要があります。また、ユーザー インターフェイスの状態と動作を制御するロジックと、データの表示とユーザーからのデータの取得を行うロジックとを分離する必要があります。

ソリューション : ユーザー インターフェイスをコントローラとビューに分離します。中間層を使用して、ビューが要求する適切なビジネス モデル要素にアクセスします。

パターンの使用時期 : 同じデータを異なるビューに異なる方法で表示または取得する可能性がある複雑なユーザー インターフェイスを備えたアプリケーションで MVC パターンを使用します。また、このパターンは、ユーザー インターフェイス層とビジネス層を完全に分離する必要があるアプリケーションに適しています。

クラス図 : 図 2.5 に MVC パターンに関係するクラスを示します。

図 2.5. Model-View-Controller (MVC) パターン

プレゼンテーション層で MVC パターンを使用する方法

  1. モデルを表すコンポーネントを特定します。モデルは、一般的に、ビジネス エンティティ、ビジネス コンポーネント、データ アクセス ロジック コンポーネント、およびサービス エージェントの組み合わせになります。要件に適用するコンポーネントを特定する方法の詳細については、このガイドの第 4 章「データの管理」を参照してください。
  2. Windows フォーム、ASP.NET ページ、コントロールなど、ユーザー インターフェイス コンポーネントとして実装する必要があるビューを作成します。User Interface Process Application Block を使用していない場合は、ビュー オブジェクトからコントローラ オブジェクトへの参照を作成し、保持する必要があります。
  3. コントローラ クラスを定義し、データ要求時や操作開始時にビューが呼び出せるメソッドを実装します。実装するメソッドにより、手順 1 で特定したモデル コンポーネントにアクセスされることになります。

以下に、Windows フォーム アプリケーションや ASP.NET アプリケーションで MVC パターンを実装する際の推奨事項を示します。

  • User Interface Process Application Block の使用が要件に適するかどうかを判断します。このブロックにより、.NET Framework アプリケーションに MVC パターンの実装テンプレートが提供されます。
  • ビューからモデル内のデータへのアクセスを読み取り専用に制限します。データを変更する必要がある場合は、ビューではなくコントローラにより変更する必要があります。この制約により、モデルとビュー間の直接の結合が取り除かれ、アプリケーション ロジックが簡潔になります。
  • 重要な状態変化を通知するためにモデル関連のイベントを発生させます。イベントの発生は、特に、複数のビューが同一モデルからのデータを表示する Windows フォーム ベースのアプリケーションに適しています。モデル関連のイベントにより、ビューはユーザーに表示されるデータを変更できるようになります。ビューで直接メソッドを呼び出すのではなく、モデルでイベントを発生させることにより、モデルとビュー間の結合性が低い状態に保ちます。
  • プラットフォームに依存しない方法でコントローラを実装し、コントローラと対話するビューの種類とは無関係にコントローラの移植性を向上します。たとえば、コントローラ クラスで ASP.NET 固有のコードまたは Windows フォーム固有のコードを記述しないようにします。
  • コントローラ クラスの単体テストを行います。コントローラはユーザー インターフェイスを提供する代わりにプログラム機能を公開しているので、簡単に単体テストを行えます。

関連情報

Application Controller パターンの使用

Application Controller パターンは、制御の流れを設定し、状態管理機能を提供し、ビューを特定のコントローラ クラスへの関連付けることによって、複数ユーザーとの対話を管理します。

問題点 : 異なるビュー間に制御の流れを設定しし、ビュー間で状態管理を行えるようにする必要があります。

コントローラ クラスとビュー クラスにコードを埋め込むことでこのような目標を実現できますが、この方法では、将来、ナビゲーションに関する変更や、コントローラとビューの追加が難しくなります。

ソリューション : Application Controller クラスを個別に作成して、コントローラ ロジックとビュー間の流れを制御します。

パターンの使用時期 : ビュー間の流れが 1 つに定まるアプリケーションで Application Controller パターンを使用します。

クラス図 : 図 2.6 に Application Controller パターンに関係するクラスとインターフェイスを示します。

図 2.6. Application Controller パターン

プレゼンテーション層で Application Controller パターンを使用する方法

  1. アプリケーション内で、他と異なるユース ケースを特定します。ユース ケースにより、特定のタスクの実行に関わる一連のユーザー アクティビティが定義されます。ユース ケースに関係するビューとユーザーとの対話に必要なコントローラを特定します。
  2. User Interface Process Application Block を使用している場合は、ユース ケースごとにナビゲーション グラフを構成します。ナビゲーション グラフにより、ユース ケース内のビュー間の流れが定義されます。ナビゲーション グラフの詳細については、この章の後半の「User Interface Process Application Block の構成方法」を参照してください。

以下に、ASP.NET アプリケーションで Application Controller パターンを実装する際の推奨事項を示します。

  • User Interface Process Application Block を使用して、アプリケーションにこのパターンを実装します。Application Controller 機能は、特に、プラットフォーム間で移植する必要がある場合、複数種類のビューをサポートする必要がある場合、またはビュー間で状態を管理する必要がある場合などに、設計や作成が単純ではなくなります。
  • アプリケーションで User Interface Process Application Block を直接使用できない場合は、このブロックに付随するドキュメントとサンプルを調べ、できる限り、ブロックに基づいて設計と実装を行います。

関連情報

User Interface Process Application Block の使用による設計パターンの実装

アプリケーションのプレゼンテーション層に適した設計パターンを選択した後は、パターンをコードで実装する段階に入ります。

.NET Framework、特に、ASP.NET と Windows フォームは、前半で説明したパターンのうち、MVC (Model-View-Controller) パターンと Application Controller パターン以外のすべてのパターンを暗黙にサポートするプログラミング モデルを提供します。除外される 2 つのパターンのいずれかを使用する場合は、Microsoft User Interface Process Application Block を使用して、アプリケーションでのこれらのパターンの実装に役立てます。

プレゼンテーション層の大部分の設計パターンの主な目標は、ユーザー インターフェイスを表示し、ユーザー操作を受け取るコードと、ビュー ナビゲーションや状態管理などの、バックグラウンド タスクを扱うコードを明確に切り分けることです。設計パターンにより、以下のような優れた慣習が支援されます。

  • ユーザー インターフェイス ナビゲーションとワークフローをユーザー インターフェイスのビューとして実装しません。実装した場合、コードが複雑になり、保守や拡張が難しくなります。このような実装では、各ユーザー インターフェイス コードが前後のステップと密接にリンクされるので、わずかなビジネス プロセスの変更が、結果として大規模な再開発や再テストにつながることになります。
  • ビューでは、アプリケーションとセッションの状態を直接操作しません。直接操作すると、各ビューには、アプリケーション ワークフローの次のステップに状態を渡す役割が生じるので、コードが扱いにくくなります。

上記の問題点を避けるには、プレゼンテーション層をユーザー インターフェイス コンポーネントとユーザー インターフェイス プロセス コンポーネントに分割する必要があります。ユーザー インターフェイス コンポーネントとユーザー インターフェイス プロセス コンポーネントは、以下のように異なるタスクを実行します。

  • ユーザー インターフェイス コンポーネントにより、ユーザーと対話するフォームやコントロールが提供されます。
  • ユーザー インターフェイス プロセス コンポーネントにより、ユーザー操作とアプリケーションとが同期、同調され、ビジネス プロセスのサポートに必要なナビゲーションやワークフローが提供されます。

ユーザー インターフェイス コンポーネントとユーザー インターフェイス プロセス コンポーネントのコンテキストの詳細については、MSDN の「.NET のアプリケーション アーキテクチャ : アプリケーションとサービスの設計」 を参照してください。

User Interface Process Application Block は、柔軟、汎用かつ再利用可能なコンポーネントで、アプリケーションで使用してユーザー プロセスを実装できます。このブロックにより、アプリケーションの進化に合わせて、再利用および容易に拡張できる複雑なユーザー インターフェイス ナビゲーションとワークフロー プロセスを記述できます。

  • このセクションのトピックを、以下に示します。
  • User Interface Process Application Block の設計
  • User Interface Process Application Block を使用する利点
  • User Interface Process Application Block でのアプリケーションのビルド

User Interface Process Application Block のダウンロードには、ブロックの設計とアプリケーションでのブロックの使用方法に関する包括的なドキュメントが含まれています。また、ブロックを使用して、プレゼンテーション層のナビゲーション フローと状態管理を簡単にする方法を説明する、サンプル "shopping cart" ASP.NET Web アプリケーションも含まれています。

User Interface Process Application Block の設計

User Interface Process Application Block は、MVC (Model-View-Controller) パターンに基づいてアプリケーションをビルドし、ユーザー インターフェイスを表示し、ユーザー操作に応答するコードと、基礎となるビジネス ロジックを実装するコードとを完全に分離するのに役立ちます。また、このブロックはビュー間の制御の流れと状態管理を処理するので、Application Controller パターンも実装します。

User Interface Process Application Block は、Windows フォームや ASP.NET アプリケーションなどの複数の種類のビュー間で使用できるコントローラを作成できるように、再利用性と拡張性を考慮して設計されています。

図 2.7 に、User Interface Process Application Block の主なコンポーネントを示します。

図 2.7. User Interface Process Application Block のコンポーネント

User Interface Process Application Block のコンポーネントにより、以下のタスクが行われます。

  • UIPManager - ユーザー インターフェイス プロセスを管理します。ビューからのコントローラの切り離し、新しいビューの生成、タスクの調整、およびワークフローに基づくナビゲーションの提供を行います。
  • ControllerBase - 基本クラスを抽象化します。MVC パターンのコントローラ クラスと等価です。主な目的は、ビュー間のナビゲーションを制御し、ユーザー インターフェイス層とビジネス層の間のインターフェイスとして機能することです。
  • State - タスクのステップ間で共有される状態を表すクラスです。ディクショナリのようなインターフェイスを実装して状態値を保持します。このクラスから継承することによって、タスクのコントローラ間で厳密に型指定された状態オブジェクトを共有できます。
  • SqlServerStatePersistenceSecureSqlServerStatePersistenceMemoryStatePersistence、および SessionStatePersistence - これらのプラグインにより、複数の場所への状態の格納と読み込みが管理されます。
  • WinFormView - Windows フォーム アプリケーションのフォームの基本クラスです。 Windows フォームの開発時にこのクラスから継承します。
  • WinFormViewManager - ユーザーを Windows フォーム間で移動するために UIPManager が使用するプラグインです。
  • WebFormView - ASP.NET Web アプリケーションのフォームの基本クラスです。 Web フォームの開発時にこのクラスから継承します。
  • WinFormViewManager - ユーザーを Web フォーム間で移動するために UIPManager が使用するプラグインです。

User Interface Process Application Block では、実装の自由度が公開されます。 拡張方法は多種多様ですが、一般的な方法は以下のとおりです。

  • 状態型 - State クラスから継承することによって、厳密に型指定された状態型を作成できます。
  • 状態の場所 - IStatePersistence インターフェイスを実装することによって、さまざまな場所で共有される状態を格納できます。State オブジェクトで保持されるデータを半永久的に格納し、State オブジェクトの再構築時に状態を取得するメソッドを記述できます。
  • ビュー - IView インターフェイスを実装することによって、カスタム コントローラを多様なコンポーネントに割り当てることができます。
  • ビューの遷移 - IViewManager インターフェイスを実装することによって、ビュー間のビジュアルな遷移をさまざまなスタイルで処理できます。

ブロックの使用方法とカスタマイズ方法の詳細については、このブロックで提供されているドキュメントのトピック「Customizing State Management」と「Customizing Views and View Management」を参照してください。(英語)

User Interface Process Application Block を使用する利点

User Interface Process Application Block は、以下の点で役に立ちます。

  • ワークフローとナビゲーションをユーザー インターフェイス層から切り離します。
  • 状態管理をユーザー インターフェイス層から切り離します。
  • Windows ベースのアプリケーション、Web アプリケーション、およびデバイス アプリケーションなど、異なる種類のアプリケーションに同一のユーザー インターフェイス プログラミング モデルを使用します。
  • タスクの概念を導入します。タスクとは、保存できるユース ケース内の対話のスナップショットです。

これらの点については、以降のセクションで詳しく説明します。ブロックの使用方法の例については、この章の後半の「User Interface Process Application Block を使用したアプリケーションのビルド」を参照してください。

ワークフローをユーザー インターフェイスから分離する

ワークフローは、Web ページ間、Windows フォーム間、または携帯電話の画面間の制御を、最終的に流れとして表す決定プロセスです。このような決定は、一般的に、バックエンド システムが行うタスクの結果に依存します。たとえば、顧客のクレジット カードの承認に対して、以下の操作が考えられます。

  • 承認が失敗したので、別のカードを使用するよう顧客に求めます。
  • 顧客に「ありがとうございます」というページを表示して、買い物を続けるかどうかを確認します。

決定を下すコードやページ リダイレクション ロジックをすべてユーザー インターフェイス コンポーネント (たとえば、ASP.NET コード ビハインド クラスなど) に記述しているなら、その開発者は扱いにくいシステム作成しています。ユーザー インターフェイス コンポーネントが互いに認識し合えるようにすると、これらのコンポーネントは緊密にリンクされます。10 ページ程度のアプリケーションの場合には、大きな障害にはなりません。しかし、500 ページのアプリケーションでは、アプリケーションの管理や拡張が難しくなる大きな問題になる可能性があります。

User Interface Process Application Block は以下のような方法で、ワークフローのユーザー インターフェイス コンポーネントからの分離を支援します。

  • XML ドキュメントで表現されるナビゲーション グラフを使用して再利用可能なワークフロー定義を定義します。ナビゲーション グラフとその他の構成設定は、ワークフローの進行方法に影響します。
  • ワークフローのすべての役割を 2 つのコンポーネント、つまり、コントローラ クラスと標準の UIPManager クラスにデリゲートします。コントローラと UIPManager は以下のように連携して、アプリケーション ワークフローを制御します。
    • コントローラでは、顧客のクレジット カードが適切に承認されたかどうかの確認などのビジネス ロジックに基づいてワークフローの次の手順が決定されます。
    • UIPManager は、コントローラから提供される結果を使用して、ワークフローの次の手順をユーザーに提示するための適切なビューを決定します。

このようにワークフローを切り離すことにより、非常に柔軟なプレゼンテーション層を作成できます。柔軟なプレゼンテーション層には、相互に独立したビュー、集中管理され、再利用可能なビジネス ロジック、および実際のユーザー インターフェイス要素自体以外はほぼ同じコードを共有できる複数の出力様式などが含まれます。

移植性の強化

多様なクライアントをサポートするために、多くのアプリケーションでは複数のユーザー インターフェイスが提供されています。たとえば、E コマースでは顧客に Web ベースのユーザー インターフェイスを提供し、管理職、販売員、サポート スタッフには Windows ベースのユーザー インターフェイスを提供している場合があります。さらに、アプリケーションの進化に伴い、個人用携帯情報端末 (PDA) や携帯電話など、新たな種類のクライアントに対するサポートにも頻繁に対応していく必要が出てきます。

共通の外観や使用モデルを各ユーザー インターフェイスで共有できますが、それらの実装と配布のメカニズムは大きく異なります。ただし、ユーザー インターフェイスは異なっていても、多くの場合、アプリケーションの利用者が使用するビジネス ロジックは、すべてのクライアントに共通しています。これに対するソリューションは、図 2.8 のように、ユーザー インターフェイス プロセス コンポーネントを定義することです。

図 2.8. 複数のユーザー インターフェイスのサポート

User Interface Process Application Block は以下の方法での、より移植性の高いアプリケーションのビルドに役立ちます。

  • 状態管理が切り離され、Windows ベースのアプリケーションと Web ベースのアプリケーションの両方で同一の状態管理メカニズムを使用できるようになります。アプリケーションの移行時に、状態管理メカニズムを作り直す必要がありません。
  • ユーザー インターフェイス要素自体の生成で、直接状態が関わる可能性がある場合を除き、ビューが状態を保持することがないようにします。
  • 1 つのエンティティで状態を集中管理することにより、ビュー間の状態の通信が管理されます。
  • すべてのビジネス ロジックとワークフロー制御をコントローラと UIPManager にデリゲートします。

ブロックでは、ユーザー インターフェイスやユーザー操作のインターセプトに直接関係しない問題がカプセル化されます。このようなタスクは、ユーザー インターフェイス コンポーネントによって行われます。アプリケーションを新しいプラットフォームに移行する必要がある場合、たとえば、Windows フォーム ベースのアプリケーションを Web アプリケーションに移行する場合は、ユーザー インターフェイス コンポーネントの再実装だけが必要になります。つまり、ユーザー インターフェイス プロセス コンポーネントのコードはそのまま再利用できます。

ユーザー インターフェイスから状態管理を分離する

伝統的なアプリケーションでは、多くの場合、状態はユーザー インターフェイス コンポーネントに直接格納されます。その結果、状態を格納し、状態にアクセスし、状態を操作するコードが複雑になります。また、このことは、状態がユーザー インターフェイスの種類に依存することも意味します。つまり、異なる種類のアプリケーション間でのコードの移植を難しくします。

ユーザー インターフェイス コンポーネントに状態を格納した場合、一般的に以下の問題点が発生します。

  • Windows フォーム アプリケーションでは、ユーザーとフォーム間での対話中に状態を保持する多くのメンバ変数をフォームが保持することになります。最も重要なシナリオでは、アプリケーションで他のフォームの状態にアクセスする必要があります。開発者は、大量の外部コードを記述し、以下の方法のいずれか、または両方を使用して、状態を捕捉し転送する必要があります。
    • 構造体または状態を管理するクラスとして状態を具体化します。
    • メンバ変数をユーザー インターフェイスの基礎となるビジネス クラスで使用します。
  • Web アプリケーションでは、ビュー間での状態の受け渡しが非常に雑然とします。 以下に例を示します。
    • クエリ文字列によりビュー間に依存関係が生じます。受け渡しをする項目の名前と基礎となる情報の種類について、両方のビューで把握しておく必要があります。
    • 隠しフォーム フィールドがクエリ文字列と同様の問題を引き起こします。
    • Cookie が、クエリ文字列や隠しフォーム フィールドと同様の問題を引き起こします。さらに、Cookie をまったく使用しないように設定しているユーザーも存在するので、Cookie に依存できない場合があります。
    • .NET Framework クラス ライブラリの Session 型、Application 型、および Cache 型を使用すると、より適切な状態で型を維持できますが、これらの型もユーザー インターフェイスを ASP.NET に密接に結び付けます。

User interface Process Application Block は以下のような方法で簡単に状態管理を行えるようにします。

  • 長時間継続しているユーザーとの対話状態を簡単に持続させることができます。そのため、ユーザー操作を簡単に廃棄し、再開できます。異なるユーザー インターフェイスを使用する場合でも同様のことが可能になります。たとえば、顧客は Web ベースのユーザー インターフェイスを使用してショッピング カートに商品を追加し、後で販売員を呼び出して注文を完了させることができます。
  • ユーザー プロセスの状態を集中管理することで、より簡単に複数の関連要素や関連ウィンドウのユーザー インターフェイスに一貫性を持たせることができます。また、集中管理されるユーザー プロセス状態により、ユーザーが同時に複数のアクティビティを実行できるようにします。
  • 状態の場所と存続期間を分離することにより、ユーザー インターフェイス コンポーネントの堅牢性を強化します。つまり、ビューは状態を検索する場所を把握していますが、状態がどこに格納されているのか、また、他のビューに状態を渡す方法を把握する必要がありません。
  • State オブジェクトの保存用に IStatePersistence インターフェイスが用意されています。State データから保存を分離することによってもたらされる柔軟性は、開発者が State オブジェクトの利用者に影響を与えることなく自由に保存を最適化できることを意味します。

このような利点から、User Interface Process Application Block の使用により、ユーザー インターフェイス プロセス機能を必要とするプレゼンテーション層の開発が簡単になるということが言えます。

User Interface Process Application Block でのアプリケーションのビルド

User Interface Process Application Block では、以下の 2 つの手順でアプリケーションをビルドします。

  • アプリケーションの要件を収集します。この作業の最初の手順では、アプリケーションを個別のユース ケースに分離します。 ユース ケースごとに、ワークフローと状態管理の要件を定義する必要があります。
  • ビューとコントローラ クラスを必要に応じて実装し、構成ファイルを作成して、アプリケーションで使用する User Interface Process Applicaiton Block を構成します。

要件の収集

以下の手順は、アプリケーションの要件の特定に役立ちます。また、User Interface Process Application Block を使用して実装に役立てる方法を決定するのに役立ちます。

  1. アプリケーションをユース ケースに分割します。
  2. ユース ケースごとにナビゲーション グラフを設計します。
  3. User Interface Process Application Block の既存の機能が要件を満たすことを確認します。
  4. タスクごとに状態保存を決定します。
  5. コントローラ クラスを設計します。
  6. ビューを設計します。

以下のセクションでは、これらの各手順を説明します。

アプリケーションをユース ケースに分割する

一般的に、アプリケーションは多くのユース ケースで構成されます。たとえば、オンライン小売アプリケーションは、商品の購入、在庫品一覧への在庫品の追加、売れ行きの悪い在庫品の一覧からの削除というユース ケースで構成されるでしょう。

各ユース ケースには、ユーザーとの特定の対話シーケンスがあります。ユース ケースを適切に分割することで、ユース ケースがカプセル化され、多くの場合、関数としてユース ケースを呼び出すことができるようになるので、さらに再利用しやすくなります。

ユース ケースごとのナビゲーション グラフを設計する

各ユース ケースに必要な制御の流れを決定し、ビュー間のビジュアルな流れとして、ユース ケースを表すナビゲーション グラフを描きます。

たとえば、図 2.9 に User Interface Process Application Block のダウンロードに含まれているサンプル アプリケーション UIProcessQuickstarts_Store のナビゲーション グラフを示します。

図 2.9. サンプルのナビゲーション グラフ

図 2.9 のナビゲーション グラフは、"browsecatalog" や "cart" など、アプリケーションの論理的ビューを特定します。また、ナビゲーション グラフは、特定のビューから他ののビューに遷移させるナビゲーション手段も定義します。たとえば、"addItem" ナビゲーション手順は "borwsercatalog" ビューから "cart" ビューに遷移させ、"resume" ナビゲーション手順は元の "borwsercatalog" ビューに遷移を戻します。

User Interface Process Application Block の既存の機能が要件を満たすことを確認する

User Interface Process Application Block には、状態保存、状態の種類、ビュー、およびビュー マネージャ用の一般的な実装が含まれています。要件を調査し、以下の領域についてブロックが十分な機能を提供するかどうかを評価します。

  • 状態の場所 (SQL Server、セキュリティで保護された SQL Server、セッション、およびメモリに状態データを格納するための組み込みサポートが提供されます)。
  • 状態の種類 (既定では、厳密に型指定されないディクショナリのような状態ストレージを使用します)。
  • ビュー管理 (Windows フォームや Web フォームのナビゲーション用の組み込みサポートが提供されます。)

ブロックの動作のこのような側面をカスタマイズする方法の詳細については、User Interface Process Application Block のドキュメントを参照してください。

タスクごとに状態保存を決定する

User Interface Process Application Block のドキュメントで使用されている用語で "タスク" は、プロセスの実行中のインスタンスです。たとえば、ユーザーは "Add Payment Method" プロセスのタスクを開始できます。タスクにより、アプリケーションとユーザー間のすべての通信状態がカプセル化されます。

各ユース ケースのタスクの存続時間は異なる場合があります。たとえば、ユーザーに、以前そのユーザーが別の Web セッションで開始したタスクや、Windows アプリケーションの終了後にタスクを再開できるようにさせたい場合があります。また、1 人のユーザーにのみタスクを関連付けることができるようにするのか、複数のユーザーに関連付けることができるようにするのかを決定する必要があります (たとえば、1 人に関連付ける例としては小売サイトでの清算が、複数のユーザーに関連付ける例としてはヘルプデスク チームのメンバ間でサポートの電話を転送することが考えられます)。

表 2.1 に、User Interface Process Application Block で使用できる 4 つの状態保存プロバイダを示します。この表を利用して、要件に最も適した状態保存プロバイダを決定してください。

表 2.1: 状態保存プロバイダの属性

状態保存プロバイダ 異なるユーザーへのタスク割り当てについての柔軟性 セッションまたははアプリケーションの存続時間全体に及ぶタスクの能力 Windows ベースのアプリケーションに対するサポート Web アプリケーションに対するサポート
SQL Server x x x x
セキュリティで保護された SQL Server x x x x
セッション       x
メモリ     x  

コントローラ クラスを設計する

User Interface Process Application Block では、ControllerBaseという名前の再利用可能なクラスが定義されています。このクラスは、アプリケーション固有のコントローラ クラスの基本クラスとして動作します。

コントローラ クラスでは、プロパティとメソッドを記述してビジネス層と相互作用し、データの取得や更新、およびビジネス関連の処理を行う必要があります。これらのプロパティとメソッドの一部を public で宣言します。その結果、必要に応じてビューがデータを表示したり、更新されたデータをコントローラに渡したりできるようになります。ビューが直接状態を変更できるようにしないでください。これは、モデルとビュー間を分離するという MVC の原則に反します。

たとえば、UIProcessQuickstarts_Store サンプル アプリケーションでは、IsUserValidAddToCart、および CheckoutOrder などのメソッドを持つ StoreController クラスが定義されています。

ビューを設計する

最後の手順は、アプリケーションのビューの設計です。一般的に、各ビューを Windows フォームまたは ASP.NET Web フォームとして実装します。各ビューは、特定のユーザー インターフェイスの表示、コントローラからのデータの取得とそのデータの表示、コントローラの他のメソッドの呼び出しなどを担当し、ビジネス関連の処理を進めていきます。

コンポーネントのビルド

要件の収集後、ユース ケースを構成するビューとコントローラを実装し、それらを相互に結び付けるように User Interface Process Application Block を構成します。

最初の手順では、アプリケーションでブロックへの参照を追加します。

User Interface Process Application Block の参照方法

  1. Visual Studio .NET を起動して、必要に応じて Windows ベースのアプリケーションまたは ASP.NET Web アプリケーションを作成します。

  2. ソリューション エクスプローラでプロジェクトを右クリックし、Microsoft.ApplicationBlocks.UIProcess.dll アセンブリへの参照を追加します。 このアセンブリが存在する場所は、アセンブリのインストール方法によって異なります。

    • このアセンブリをグローバル アセンブリ キャッシュにインストールした場合は、GAC からアセンブリを参照できます。
    • それ以外の場合は、C:\Program Files\Microsoft Application Blocks for .NET\User Interface Process\Code\CS\Microsoft.ApplicationBlocks.UIProcess\bin\Debug のような、インストール フォルダからアセンブリを参照する必要があります。
  3. ブロックのクラスを使用する各ソース ファイルで、using ステートメントを追加し Microsoft.ApplicationBlocks.UIProcess 名前空間を参照します。すべての User Interface Process Application Block 型がこの名前空間に含まれています。

    using Microsoft.ApplicationBlocks.UIProcess;
    
    

ビューの作成方法

  1. Windows ベースのアプリケーションをビルドしている場合は、Windows フォーム クラスのソース コードを表示します。フォーム クラスの定義で、基本クラス System.Windows.Forms.Form を削除し、WinFormView基本クラスに置き換えます。

    public class MyWindowsForm : WinFormView
    
    

    ASP.NET Web アプリケーションをビルドしている場合は、Web フォーム クラスのソース コードを表示します。フォーム クラスの定義で、基本クラス System.Web.UI.Page を削除し、WebFormView 基本クラスに置き換えます。

    public class MyWebForm : WebFormView
    
    
  2. プライベート プロパティ "getter" を作成して、アプリケーションのコントローラ オブジェクトへの参照を返します。

    WinFormView 基本クラスまたは WebFormView 基本クラスで定義されている静的プロパティ Controller を使用してコントローラ オブジェクトにアクセスします。アプリケーションのコントローラ クラスの実際の型にコントローラ オブジェクトをキャストします。

    private StoreController StoreController
    {
      get{ return (StoreController)this.Controller; }
    }
    
    
  3. コードを追加して、データベースからのデータの取得、データベースへのデータの保存、プロセス内の次のフォームへの移動などのタスクをビュー クラスが実行するようにします。これらのタスクは、コントローラ クラスのメソッドによって実装されます。つまり、これらのタスクをビューから実行させるために、このコントローラ オブジェクトの適切なメソッドを呼び出します。

    次の例では、コントローラの AddToCart という名前のメソッドを呼び出し、ユーザーのショッピング カートに特定の商品の数量を加算しています。

    StoreController.AddToCart(productID, quantity);
    
    
  4. ビュー クラスにコードを追加して、コントローラ オブジェクトからの状態情報を必要に応じて取得します。 コントローラ オブジェクトにはパブリック プロパティ State があります。このプロパティを使用して、状態の項目名の取得や設定を行えます。また、このプロパティによって、Windows ベースのアプリケーションと Web アプリケーションの状態管理が容易になります。

    次の例では、CustomerNameState という名前の状態項目の値を取得しています。

    customerNameLbl.Text = StoreController.State["CustomerNameState"].ToString();
    
    

    コントローラ オブジェクトにより、状態管理に関する実装の詳細がすべてカプセル化されます。ビュー クラスのコードは、状態がどこから取得され、どこに格納されるのかについては関わりません。

コントローラ クラスの作成方法

  1. Visual Studio .NET を使用して新しいクラスを作成します。

  2. ControllerBase からこのクラスを継承させます。

    public class StoreController : ControllerBase
    {
      // ...
    }
    
    
  3. State パラメータを受け取り、基本クラスの該当するコンストラクタを呼び出すコンストラクタを追加します。

    public class StoreController : ControllerBase
    {
        public StoreController( State controllerState ) 
            : base( controllerState ){}
        //...
    }
    
    
  4. コントローラ クラスのヘルパ プロパティを記述して状態管理に利用します。

    次の例では、Cart プロパティが CartState という名前の状態項目を取得し設定しています。CartState は、ユーザーのショッピング カートを保持するハッシュ テーブルです。

    private Hashtable Cart
    {
      get
      {
        Hashtable cart = (Hashtable)State["CartState"];
        if (cart == null)
        {
          cart = new Hashtable();
          State["CartState"] = cart;
        }
        return cart;
      }
      set
      {
        State["CartState"] = value;
      }
    }
    
    
  5. コントローラ クラスにパブリック メソッドを記述して、状態項目へのアクセスを制御します。

    次の例では、AddToCart メソッドがユーザーのショッピング カートに特定の商品の数量を加算しています。

    public void AddToCart(int productID, int quantity)
    {
      if (Cart.Contains(productID))
      {
        // 商品 ID が既にカートに入っているので単純に数量をインクリメントします
        int existingQuantity = (int)Cart[productID];
        Cart[productID] = existingQuantity + quantity;
      }
      else
      {
        // 商品 ID がまだカートに入っていないので、この商品 ID を挿入します
        Cart[productID] = quantity;
      }
    }
    
    
  6. コントローラ クラスにパブリック メソッドを記述し、ユーザー インターフェイス プロセスの現在の手順を変更します。現在の手順を変更するには、State オブジェクトの NavigateState プロパティを設定し、Navigate メソッドを呼び出します。UIPManager が構成を確認し、結果を表示する必要があるビューかどうかを判断します。その後、現在の NavigationGraphViewManager を使用して次のビューに遷移します。

    以下のメソッドは、現在のショッピング タスクを停止し、再開する方法を示しています。

    public void StopShopping() 
    {    
      // 次のビューに進みます
      State.NavigateValue = "stop";
      Navigate();
    }
    
    public void ResumeShopping() 
    {
      // 次のビューに進みます
      State.NavigateValue = "resume";
      Navigate();
    }
    
    

    以下のメソッドは、清算を完了する方法を示しています。メソッドがユーザーのクレジット カードの詳細を検証し、結果に応じて "failCheckout" または "successCheckout" に進みます。

    public void CompleteCheckout( string name, string addr, string ccnum )
    {
      if ( … クレジット カード検証コード … )
      {
        State.NavigateValue = "failCheckout";
      }
      else
      {
        State.NavigateValue = "successCheckout";
      }
      Navigate();
    }
    
    

    これらの例では、コントローラのコードが特定のビューにハードコードされたリンクをまったく含んでいないことに注意してください。代わりに、ナビゲーション手順とビュー間の関係は、ナビゲーション グラフでの宣言で指定されます。そのため、コントローラ クラスはビュー クラスにも、各ユース ケースのビューの順序にも直接依存しません。

User Interface Process Application Block の構成方法

ここでは、User Interface Process Application Block を構成してビュー間の制御の流れを定義し、アプリケーションの状態管理情報を指定する方法を説明します。

ブロックの構成方法の完全な情報については、ブロックで提供されているドキュメントで「Creating the Configuration File」を参照してください。

  1. アプリケーションの構成ファイルを開きます。

    • ASP.NET Web アプリケーションの場合、構成ファイルは ASP.NET プロジェクトの Web.config になります。
    • Windows フォーム アプリケーションの場合は、アプリケーションの実行可能ファイルと同じフォルダに ApplicationName.exe.config という名前の構成ファイルを作成します。構成ファイルは、<configuration> という名前のルート要素を持つ必要があります。
  2. 構成ファイルの <configSections> 要素に、新しい構成セクションを以下のように定義します。

    <configuration>
      …
      <configSections>
        <section name="uipConfiguration"
                 type="Microsoft.ApplicationBlocks.UIProcess.UIPConfigHandler,
                       Microsoft.ApplicationBlocks.UIProcess" />
      </configSections>
      …
    </configuration>
    
    
  3. <uipConfiguration> という名前の新しい構成セクションを作成します。 このセクションは、アプリケーションがビュー管理、状態管理、およびコントローラに使用するクラス、つまり、ユーザーが使用できるビューと、それらビュー間全体のワークフロー パスを定義するナビゲーション グラフを設定するためにアプリケーションが使用するクラスを定義するために使用されます。

    <uipConfiguration> セクションの構造は、ブロックに含まれている UIPConfigSchema.xsd XML スキーマ ドキュメントで定義されます。このスキーマは、必須の要素と属性、省略可能な要素と属性、発生する頻度、それらを表示する順序などを指定します。<uipConfiguration> セクションがこのスキーマに従っていない場合、実行時に例外が発生します。

    <configuration>
      …
      <uipConfiguration enableStateCache="true">
        <objectTypes>
          … アプリケーション中の該当クラスを識別します …
        </objectTypes>
        <views>
          … ユーザーが使用できるビューを識別します …
        </views>
        <navigationGraph>
          … ナビゲーション グラフを定義します …
        </navigationGraph>
      </uipConfiguration>
      …
    </configuration>
    
    
  4. <objectTypes> 要素で詳細を指定して、アプリケーションの関連クラスを特定します。以下の情報を <objectTypes> に追加する必要があります。

    <objectTypes>
    
      <iViewManager 
        name="ビュー マネージャ クラスの名前"
        type="ビュー マネージャ クラスの型"/>
    
      <state 
        name="状態管理クラスの名前"
        type="状態管理クラスの型"/>
    
      <controller
        name="コントローラ クラスの名前"
        name="コントローラ クラスの型">
    
      <statePersistenceProvider
        name="状態保存プロバイダ クラスの名前"
        name="状態保存プロバイダ クラスの型"
        connectionString="状態管理のデータ ソースへの接続文字列"/>
    
    </objectTypes>
    
    

    次の例では、User Interface Process Application Block のダウンロードに含まれている UIProcessQuickstarts_Store サンプル アプリケーションの構成ファイルの <objectTypes> 要素を示します。

    <objectTypes>
    
      <iViewManager 
        name="WebFormViewManager"
        type="Microsoft.ApplicationBlocks.UIProcess.WebFormViewManager, 
              Microsoft.ApplicationBlocks.UIProcess, Version=1.0.1.0,
              Culture=neutral, PublicKeyToken=null"/>
    
      <state 
        name="State" 
        type="Microsoft.ApplicationBlocks.UIProcess.State, 
              Microsoft.ApplicationBlocks.UIProcess, Version=1.0.1.0,
              Culture=neutral, PublicKeyToken=null"/>
    
      <controller
        name="StoreController" 
        type="UIProcessQuickstarts_Store.StoreController, 
              UIProcessQuickstarts_Store.Common, Version=1.0.1.0,
              Culture=neutral, PublicKeyToken=null" />
    
      <controller
        name="SurveyController" 
        type="UIProcessQuickstarts_Store.SurveyController,
              UIProcessQuickstarts_Store.Common, Version=1.0.1.0,
              Culture=neutral, PublicKeyToken=null" />
    
      <statePersistenceProvider
        name="SqlServerPersistState"  
        type="Microsoft.ApplicationBlocks.UIProcess.SqlServerPersistState, 
              Microsoft.ApplicationBlocks.UIProcess, Version=1.0.1.0,
              Culture=neutral, PublicKeyToken=null"
        connectionString="Data Source=localhost;Initial Catalog=UIPState;
                          user id=UIP;password=U1Pr0c3ss"/>
    
    </objectTypes>
    
    
  5. <views> 要素で詳細を指定して、アプリケーションで使用できるビューを特定します。以下の情報を <views> に追加する必要があります。

    <views>
    
      <view 
        name="ビューの論理名"
        type="ビューの ASP.NET ファイル"
        controller="このビューのコントローラ クラスの名前"/>
    
      … アプリケーションのその他のビューの <view> 要素を追加します …
    
    </views>
    
    

    次の例は、User Interface Process Application Block のダウンロードに含まれている UIProcessQuickstarts_Store サンプル アプリケーションの構成ファイルの <views> 要素を示します。

    <views>
    
      <view 
        name="cart" 
        type="cart.aspx" 
        controller="StoreController" />
    
      <view 
        name="browsecatalog" 
        type="browsecatalog.aspx" 
        controller="StoreController" />
    
      <view 
        name="error" 
        type="uipError.aspx" 
        controller="StoreController" />
    
      <view 
        name="congratulations" 
        type="congratulations.aspx" 
        controller="StoreController" />
    
      <view 
        name="checkout" 
        type="checkout.aspx" 
        controller="StoreController" />
    
      <view 
        name="survey" 
        type="survey.aspx" 
        controller="SurveyController" />
    
    </views>
    
    
  6. 以下のように、<navigationGraph> 要素で詳細を指定します。

    • <navigationGraph> には、プロセス名、開始ビュー、ViewManager の型、共有する状態の種類、およびプロセスに適した状態保存プロバイダを指定する属性があります。
    • <navigationGraph> には、ナビゲーション グラフのノードを識別する <node> 要素もあります。

    <navigationGraph> の構造を以下に示します。

    <navigationGraph
        name="このナビゲーション グラフの名前"
        startView="このナビゲーション グラフの最初のビューの論理名"
        iViewManager="ビュー マネージャの名前"
        state="状態型の名前"
        statePersist="状態保存メカニズムの名前">
    
      <node view="ビューの名前">
        <navigateTo navigateValue="ナビゲーション手順" 
                    view="遷移先のビュー、そのときの navigateValue の値"/>
        … その他のナビゲーション手順の <navigateTo> 要素を追加します。 …
      </node>
    
      … その他のビューの <node> 要素を追加します …
    
    </navigationGraph>
    
    

    次の例は、User Interface Process Application Block のダウンロードで提供されている UIProcessQuickstarts_Store サンプル アプリケーションのナビゲーション グラフを示します。

    <navigationGraph
        iViewManager="WinFormViewManager"
        name="Shopping" 
        state="State" 
        statePersist="SqlServerPersistState"
        startView="cart">
    
      <node view="cart">
        <navigateTo navigateValue="resume"   view="browsecatalog" />
        <navigateTo navigateValue="checkout" view="checkout" />
        <navigateTo navigateValue="fail"     view="error" />
        <navigateTo navigateValue="stop"     view="cart" />
      </node>
      <node view="browsecatalog">
        <navigateTo navigateValue="addItem" view="cart" />
        <navigateTo navigateValue="fail"     view="error" />
      </node>
      <node view="error">
        <navigateTo navigateValue="resume"  view="cart" />
      </node>
      <node view="checkout">
        <navigateTo navigateValue="successCheckout"  view="congratulations" />
        <navigateTo navigateValue="failCheckout"     view="checkout" />
      </node>
      <node view="congratulations">
        <navigateTo navigateValue="resume"  view="cart" />
      </node>
    
    </navigationGraph>
    
    

    ナビゲーション グラフの構成は、要件で特定された制御の流れに大きく関わり、ユーザー インターフェイス プロセスの設計の主要なオプションを明確に表します。

まとめ

この章では、設計パターンを使用してプレゼンテーション層の一般的な問題を解決する方法を説明しました。.NET Framework では、Windows フォーム アプリケーションと ASP.NET Web アプリケーションでこれらのパターンの大部分について、組み込みサポートが提供されます。さらに、Microsoft User Interface Process Application Block は Model-View-Controller パターン、Application Controller パターンをサポートし、ユーザー インターフェイスのコードとユーザー インターフェイス プロセスのコードを分離できるようにします。このブロックをアプリケーション作成の開始時に使用し、プレゼンテーション層ソリューションのベスト プラクティスの実装に役立てることができます。

先頭に戻る | 前のページ | 次のページ

Patterns & Practices ホーム