n階層システム設計の考慮点

第6回WCFとWFを統合したアプリケーションの設計について

.NET Framework 3.0以降では、WF(Microsoft Windows Workflow Foundation)とWCF(Windows Communication Foundation)を使用してアプリケーション構築ができるようになりました。これにより、ビジネスレイヤで定義されたビジネスエンティティをインターフェイスとして、WCF経由でさまざまなアプリケーションと接続するシステムを容易に構築できるようになりました。

WFを使用することで、ビジネスレイヤ内のビジネスコンポーネントの流れの制御や外部アプリケーションとの連携、状態遷移を用いたロングトランザクションの制御も比較的容易にできるようになりました。そして、WFとWCFを連携することにより、より効率的にビジネスレイヤをサービスとして公開することができるようになりました。WFからWCFを含んだカスタムアクティビティを呼び出すことによって、さまざまな分散システム技術で公開されたサービスと連携できるようにもなりました。

そこで、今回はWCFとWFを統合したアプリケーションの設計の注意点とノウハウについて説明したいと思います。

その前にここで、WFとWCFの機能についておさらいをしたいと思います。

① WFの機能

WFは、Windowsプラットフォームでワークフローソリューションを開発するための拡張フレームワークです。WFは、ワークフローベースのアプリケーションの開発および実行のためのAPIおよびツールを提供します。

ワークフローでは宣言式の長時間実行プロセスとしてプログラムを表現することができます。WFは、シーケンシャルワークフローとステートマシンワークフローを含む、さまざまなカテゴリのアプリケーションの構築環境が提供されています。

WFは、ワークフローエンジン、.NETで管理されたAPI、ランタイムサービスが提供されており、開発環境としてMicrosoft Visual Studio 2005およびMicrosoft Visual Studio 2008と統合された視覚的なデザイナとデバッガが提供されています。

図1 Visual Studio 2005に統合されたビジュアルデザイナー
図1 Visual Studio 2005に統合されたビジュアルデザイナー

WFでは、クライアントおよびサーバの両方に及ぶワークフローの構築および実行が可能であり、すべてのタイプの .NETアプリケーション内で実行可能なワークフローを作成できます。

WFで使用される用語はおもに2つです。

ワークフロー

ワークフローは、アクティビティのマップとして定義されたヒューマンプロセスまたはシステムプロセスのモデルです。

ワークフローベースのプログラムは、宣言XAMLExtensible Application Markup Language文書内に指定されます。これは、ドメイン固有アクティビティの見地からプログラムの構造を指定する文書です。

アクティビティ

アクティビティは、ワークフローのステップであり、ワークフローの実行、再利用、および構成の単位です。

アクティビティのマップは、ルール、アクション、状態、およびそれらの関係を表します。アクティビティを配置してデザインされたWFのワークフローは、.NETアセンブリにコンパイルされ、ワークフローランタイムおよび共通言語ランタイム(移行CLRと略します)で実行されます。

アクティビティは、C#あるいはVisual Basicなどの従来のCLRベースのプログラミング言語で実装されます。

WFベースのアプリケーションは、相互に接続されたコンポーネントによって構成され、これらのコンポーネントは Microsoft .NETコードによってバックアップされ、ホストアプリケーションで実行されます。

また、管理サービスを活かすことで、ワークフローの状態のイベント化、追跡、あるいはクエリを介して、個々のワークフロー プログラムの状態を検査することもできます。

② WCFの機能

WCFでは、ネットワーク分散サービスを構築、構成、および展開することができます。

WCFは主にWCFランタイムと、ASP.NET Web Services(ASMX⁠⁠、Web Service Enhancements(WSE)拡張、Microsoft メッセージキュー(MSMQ⁠⁠、Enterprise Services/COM+ランタイム環境、および .NET Remotingなどの分散システム技術をサポートしているライブラリで構成されています。

WCFは設計時にこれらのさまざまな分散システム技術を選択する必要性をなくし、1つのテクノロジプラットフォームに関する要件を組み合わせて実装できるようなります。これにより、プログラマーはそれぞれの分散システム技術間で接続に必要となるトランスポート、プロキシメカニズム、および通信チャネルの動作方法等といった個別の技術について習得する必要がなくなります。ただし、プログラマーはこれらの技術ついて勉強し、理解しておくことが望ましいでしょう。

図2 WCFの基本概念
図2 WCFの基本概念
(出典:Microsoft社 MSDNライブラリ)

WCFで使用される用語は主に3つです。そしてそれらはWCFサービスの記述(および構成)に必ず使用される3段階のプロセスとなります。

アドレス(Address)

コントラクトのエンドポイントを、ネットワークアドレスに紐付けて(バインディング定義を使用、すなわち名前によって)展開します。

バインディング(Binding)

トランスポートに加え、サービス品質、セキュリティ、およびその他のオプションを指定するサービスのバインディングを選択または定義します。

コントラクト(Contract)

コントラクトを定義してサービス上で実装します。

ここで、コントラクトにはサービスコントラクトとデータコントラクトがあります。

サービスコントラクトはインターフェイスの形態とルール、および関連するメッセージと操作を定義します。データコントラクトは操作の入出力メッセージを介して交換されるデータの形態とルールを定義します

これらの 3つの要素が独立していることはとても重要です。

これらがそれぞれ独立していることにより、コントラクトは多数のバインディングをサポートでき、バインディングは多数のコントラクトをサポートできます。

サービスは、多数のコントラクトのエンドポイントを共存させ、同時に有効化することができます。

これにより、たとえばHTTP 経由でSOAP 1.1を使用したWebサービスを公開し、さらにTCP経由で通信されるサービスを公開するといったことを同じサービス上に共存させることができます。

③ WCFとWFを統合したアプリケーションの設計手順

WCFとWFを統合したアプリケーションを設計する場合、まず、WFを用いて業務の流れを考え、設計することから始めます。ここで、WCFのことも一緒に考えだすと混乱が生じることが多いため、まずは業務の流れからWFを設計することに専念したほうがよいでしょう。

対象業務の流れの把握

まずは業務の流れを把握することから始めます。これには一般的にはビジネスフローダイアグラムやビジネスワークフォローなどが用いられます。

最初はできるだけ細かい単位で作成します。慣れてきたらそれぞれのビジネスフローダイアグラムやビジネスワークフォロー間の接続や連携、実行順等の制御の必要性などが分かってくると思われます。

これにより、業務の流れが整理され、どの部分をWFで実現すればよいか明確化できます。

これができたら、WFで実現する部分のシナリオを作成します。シナリオを作成することで、WF内で実行すべきロジック、条件分枝や扱うデータなどが明確化されます。

WFの適用検討

シナリオができたらWFでの設計を検討します。その際、シーケンシャルワークフローかステートマシンワークフローを使用するか、選択することとなります。

この2種類の選択基準は以下のようになります。

シーケンシャルワークフロー

比較的単純な業務の流れで、処理が継続的に流れていく場合。ただし、処理は必ず処理開始から処理終了まで流れる。

一般的にワークフローで実現できる場合が多い。

図3 シーケンシャル・ワークフローの例
図3 シーケンシャル・ワークフローの例
ステートマシンワークフロー

イベントにより呼び出され、状態が変化していく。状態は必ず初期状態から始まり、最終状態で終わる。状態の遷移までには時間がかかることもある。

一般的にワークフローではなく、状態遷移図で設計する。

図4 ステートマシンワークフローの例
図4 ステートマシンワークフローの例

どちらのワークフローを使用するか選択し決定したら、シナリオをフローチャートや状態遷移図で記述します。

シーケンシャルワークフローを選択しワークフローを書き始めたが、作成している途中で以下の点で悩んだり作業が滞った場合、その部分だけでも状態遷移図を書いてみてください。それですんなりいく場合はその部分だけでもステートマシンワークフローを採用するほうがいいかもしれません。

その場合はアプリケーションを分けてそれぞれを連携させる方式にしたほうがよいでしょう。

WFの設計

今回のWFの設計時にはWCFと連携していることを意識して設計する必要がります。

それは通常のWFの設計であれば、プレゼンテーションレイヤ、サービスインターフェイスやビジネスコンポーネントからの呼び出しでインスタンス化され実行されます。しかし、WCFと連携する場合はWCFから呼び出されることがあります。そのため、ワークフローはどの状態にあっても再利用されることを意識した設計をする必要があります。つまり、各アクティビティ内で初期化処理、終了処理を必ず実装します。

また、このようなサービスを設計する場合にはサービスホストの作成時にアクティブになる拡張クラスを用います。拡張クラスはワークフローランタイムのグローバルインスタンスの作成および管理をします。これにより、独立して生成されるサービスインスタンスはこのグローバルインスタンスにアクセスできるようになります。

ただし、以下の点に注意して設計する必要があります。

異なるクライアントから同じワークフローインスタンスを呼ばない

グローバルインスタンス化されたワークフローは、さまざまなクライアントから呼び出すことができます。しかし、既に呼ばれているインスタンスを別のクライアントから呼び出されるとエラーが返されることになります。これは既に呼び出されているクライアントからのバインディング時にユニークなGUIDが生成され、保持されています。そのため、別のクライアントから呼び出された時にこのGUIDの不一致によりエラーが発生してしまいます。

持続ワークフローサービスを利用してネットワーク共有から異なるクライアントでステータスが同じワークフローインスタンス呼ばない

これも同様に既に呼び出しているクライアントとのGUIDの不一致によりエラーが発生してしまいます。

WCFの設計

WFと連携してサービスとして公開する場合、WCFのサービスコントラクトにはビジネスロジックは記述しません。その代わり、ビジネスロジックをカプセル化したWFで作成されたワークフローを呼び出すイベント制御、管理するコードを実装するための設計を行います。その際、グローバルインスタンス化するワークフローランタイムの呼び出し、初期化も含めて設計します。

データコントレクトにはワークフローとデータをやり取りするためのデータを設計します。この際、ワークフローが複数のデータをパラメータとしてやり取りする場合、これらを一つのクラスとして扱えるようにラッピングします。

また、呼び出したワークフローからの応答を待つように設計する必要があります。厳密にワークフローと同期をとる必要がある場合は、ワークフローの実行スケジュールを手動で設定できる方法を検討します。

これによりWCFを経由してWFのワークフローがサービスとして公開されることになります。こうして公開されたサービスは、通常のWCFで公開されたサービスとなんら変わることなく呼び出すことができます。

その他のアドレス、バインディングについては通常のWCFと同じように設計します。

④ WCFとWFを統合したアプリケーションの設計時の注意点

このように、WCFとWFを統合すると、ワークフローをサービスとしてさまざまな分散システム技術を通して公開することが容易にできます。また、公開されたサービスをWFから使用することもできます。しかし、次の点について考慮する必要があります。

ワークフローでカスタムメイドしたWCFを含むアクティビティは多用しない

ワークフローとサービスは基本的に非同期で実行されます。そのため、WCFを含むアクティビティを使用する場合、意図しない時間がかかることがあります。また、WCFでの通信にはコストがかかるものもあります。これらを多用することにより、リソースを圧迫することもあります。

長時間ワークフローをWCFと連携して構築してサービス化する場合はリソースに注意する

長時間ワークフローでは途中経過のデータを保持する必要があります。これらは通常セッションとして保持されますが、WCFと連携する場合、連携時に生成されたデータも保持する必要があります。これにより、設計時には意図しなかったリソースを圧迫することもあります。

Webサービスとして公開する場合はさまざまな入力アクティビティを用意する必要がある場合がある

Webサービスとして公開する場合、接続されるクライアントが多枝にわたる場合があります。そのため、それぞれのクライアントにあったプロパティを持ったアクティビティを作成する必要があります。ここで、動的なプロパティを持ったWCFの構築を検討する方法もありますが、あまりお勧めできません。なぜならば管理が煩雑になるばかりでなく、実行が遅くなる可能性があります。

⑤ .NET Framework 3.5でのWCFとWFの統合

.NET Framework 3.5ではWFに2つのアクティビティが追加されました。

ReceiveActivity

図5 ビジュアルデザイナー上のReceiveActivity
図5 ビジュアルデザイナー上のReceiveActivity

WCFサービスコントラクトによって定義された操作を実装するサービス側アクティビティ。

ワークフローでWCFサービスコントラクトに定義された操作を実装する場合は、ReceiveActivityアクティビティが使用されます。ReceiveActivityは既に定義されたサービスコントラクトの操作を実装できるか、またはワークフロー自体内のサービスコントラクトおよび操作を定義できます。後者はワークフロー優先コントラクトと呼ばれます。

ReceiveActivityアクティビティでは、定義済みメッセージの交換パターンのセットをサポートします。次のようなパターンが含まれます。

一方向の受信

メッセージを送信するクライアントは、応答を送信するサービスを想定していません。

図6 一方向の受信イメージ
図6 一方向の受信イメージ
要求の受信 - 応答の送信

メッセージはReceiveActivityアクティビティによって受信および処理されてから、応答はクライアントに送信されます。

図7 要求の受信 - 応答の送信イメージ
図7 要求の受信 - 応答の送信イメージ
要求の受信 - エラーの送信

メッセージはReceiveActivityアクティビティによって受信および処理されてから、応答またはエラーはクライアントに送信されます。

図8 要求の受信 - エラーの送信イメージ
図8 要求の受信 - エラーの送信イメージ
(出典:Microsoft社 MSDNライブラリ)

SendActivity

図9 ビジュアルデザイナー上のSendActivity
図9 ビジュアルデザイナー上のSendActivity

WCFサービス操作の同期呼び出しをモデル化するクライアント側アクティビティ。

SendActivityアクティビティを使用すると、定義済みメッセージ交換パターンを使用してWCFサービスとのメッセージ交換に参加することができます。SendActivityアクティビティでサポートされるメッセージ交換パターンには、次が含まれます。

一方向の送信メッセージ

SendActivityアクティビティはメッセージを送信しますが、サービスからの応答を想定していません。

図10 一方向の送信メッセージイメージ
図10 一方向の送信メッセージイメージ
要求を送信し、応答を読み取り

SendActivityアクティビティはメッセージを送信し、応答をサービスから受信するまで待ちます。

図11 要求を送信し、応答を読み取りイメージ
図11 要求を送信し、応答を読み取りイメージ
要求を送信し、エラーを読み取り

SendActivityアクティビティはメッセージを送信し、応答またはエラーをサービスから受信するまで待ちます。

図12 要求を送信し、エラーを読み取りイメージ
図12 要求を送信し、エラーを読み取りイメージ
(出典:Microsoft社 MSDNライブラリ)

これらのアクティビティが追加されたことにより、WCFとの統合がとても容易になりました。しかし、前述したような作業手順および注意点はあまり変わりません。

今まではWFからWCFの呼び出しを行う場合、各操作ごとにカスタムアクティビティを作成し、これをワークフローに追加する必要がありました。しかし、.NET Framework 3.5から新しく追加された2つのアクティビティから、既に作成されているWCFサービスを呼び出す設定をするだけで作成することができるようになりました。これは作業手順、工数の大幅な削減が図ることができます。

また、今回の変更はアプリケーション開発者だけにとどまらず、Microsoft SharePoint ServicesやBizTalk等といった製品にも影響を与えています。今後、これらの機能を利用したアプリケーション構築はますます増えることと思われます。

おすすめ記事

記事・ニュース一覧