更新日: 2010 年 4 月 9 日

Visual Basic の内容はこちらに掲載しています。10 行でズバリ !! ワークフローを使用したサービスの作成 (ワークフロー サービス) (VB)

このコンテンツのポイント

.NET Framework 4 のWCF と WF を連携して、ワークフロー サービス (Workflow Services) を作成する方法を理解する

今回紹介するコード

(今回、コードはありません)

目次

  1. ワークフロー サービスの構築と処理の流れ
  2. 作成するアプリケーションの概要
  3. ワークフロー サービスで使用するアクティビティについて
  4. Request-Reply のための Correlation を設定する
  5. オペレーション名と、引数、返り値を設定する
  6. 処理を作成する
  7. サービスの名前と構成を設定する
  8. サービスを配置する
  9. 動作を確認する (クライアントの作成)

1. ワークフロー サービスの構築と処理の流れ

10 行でズバリ !! サービスの作成 (WCF) (C#) で紹介しているように、WCF (Windows Communication Foundation) を使用すると、ネットワークを経由して呼び出し可能なサービスを柔軟に作成することができます。.NET Framework 4 以降では、この WCF を使用して通信をおこない、WF (Windows Workflow Foundation) を使って内部の処理 (ロジックの実行) をおこなうワークフロー サービス (Workflow Services) を作成するためのフレームワークを持っています。ここでは、このワークフロー サービスの構築方法を説明します。

ワークフロー サービスの構築では、このあと見ていくように、.xamlx の拡張子のファイルを構築していきますが、これは、10 行でズバリ !! ワークフローの作成 (WF) (C#) で紹介した .xaml ファイルと同様の XAML フォーマットの XML ファイルです。(このため、処理そのものは、10 行でズバリ !! ワークフローの作成 (WF) (C#) で紹介した手順とほぼ同様の手順でワークフローを構築できます。)

ワークフローの作成が終了すると、このあと見ていくように、この .xamlx ファイルを含むプロジェクトを IIS (Internet Information Services) に配置します。.NET Framework 4 がインストールされた IIS では、拡張子 .xamlx のハンドラーが含まれており、クライアントなどからこの拡張子のファイルにアクセスすると、決められたパイプライン処理に沿って.NET Framework を呼び出してワークフローを実行します。

ページのトップへ


2. 作成するアプリケーションの概要

今回は商品の購入をおこなうためのサービス (アプリケーション) を構築します。ここでは、簡単なサンプル コードを使用して動作確認をおこなうため、まず、ユーザー Id (UserId) を渡して、カートの情報 (CartData) を取得するだけの簡単なサービスを作成します。(10 行でズバリ !! ワークフロー サービスにおける状態の維持 (Correlation の使用) (C#) では、このサービスに、さらに商品の購入がおこなえるように拡張していきます。)

なお、取得するカートの情報 (CartData) には、カート Id (CartId)、ユーザー Id (UserId)、現在の合計金額 (TotalCost) を含んでいます。

ページのトップへ


3. ワークフロー サービスで使用するアクティビティについて

以下の手順で、Visual Studio を起動して、新規にプロジェクトを作成します。

[ファイル] メニューの [新規作成] を選択して、[プロジェクト] をクリックします。表示される [新しいプロジェクト] ダイアログ ボックスの左のペインで [Visual C#] ノードを展開し、[Workflow] をクリックします。図 1 の通り、テンプレートとして [WCF ワークフロー アプリケーション] をクリックします。(なお、ダイアログ ボックス上部のターゲット フレームワークとして、「.NET Framework 4」を選択してください。)

図 1. プロジェクト テンプレートを選択してプロジェクトを作成

プロジェクトを作成すると、ソリューション エクスプローラーに Service1.xamlx という名称のファイルが表示されますので、これをダブルクリックすると下図のデザイナーが表示されます。

図 2. ワークフローのデザイナー (.xamlx)

このデザイナーでは、冒頭で記載したように、通常のワークフローの構築と同じ手順で処理を作成することができます。(ワークフローの作成方法については、10 行でズバリ !! ワークフローの作成 (WF) (C#) を参考にしてください。) この WCF/WF 連携サービスでは、通常のアクティビティに加え、さらに以下のアクティビティを使用することができます。

Receive アクティビティ 作成しているワークフロー サービス (WCF/WF 連携サービス) で、クライアントから処理を受け取る際に使用します。このアクティビティは、あくまでも外部の要求を受け付ける (Receive する) だけであり、その要求に応答するには、つぎの SendReply アクティビティと一緒に使用します。
(逆に、応答を伴わない One-Way な通信では、この Receive アクティビティのみを使用します。)
SendReply アクティビティ 上記のReceive アクティビティに渡された要求に応答する場合、この SendReply アクティビティを使用します。(このため、通常は、上記の Receive アクティビティと共に使用します。)
Send アクティビティ 逆に、このワークフローの内部から、外部のサービスを呼び出す際に使用するアクティビティです。上記の Receive アクティビティ同様、呼び出した結果を受け取るには、つぎの RecieveReply を一緒に呼び出します。
ReciveReply アクティビティ 上記の Send アクティビティで呼び出した結果を受け取る際に、この ReciveReply アクティビティを使用します。(このため、通常は、上記の Send アクティビティと共に使用します。)

このように、Request-Reply 型の通信をおこなう場合でも、要求と応答がアクティビティとして分離されています。これにより、例えば、ワークフローどうし (2 つのワークフロー) を連携する処理では、処理を渡してから要求を受け取るまでの間も独自の処理を作成できるため、要求側のワークフローも待機をおこなうことなく、要求側/応答側の双方で並列な処理をおこなうことができます。

プロジェクトを作成すると、図 2 (上図) のように、あらかじめ処理のためのひな形となるワークフローが作成されていますが、今回は、これを使用せずに最初からワークフローの作成をおこなうため、いったん図 2 の「Sequential Service」のアクティビティを削除します。(この Sequence アクティビティにはいくつかの変数も設定されていますが、これらもすべて削除されます。)
下図 (図 3) の通りになります。

図 3. アクティビティの削除 (クリア)

ページのトップへ


4. Request-Reply のための Correlation を設定する

では、ワークフローの作成をおこないましょう。

図 3 で、ツール ボックスから、[ReceiveAndSendReply] をデザイナー上にドラッグ・アンド・ドロップします。すると、下図 (図 4) の通り、上記で説明した Receive アクティビティと SendReply アクティビティ (下図の「SendReplyToReceive」) の 1 組が挿入された Sequence アクティビティが挿入されます。

図 4. Receive アクティビティと SendReply アクティビティの挿入

この Receive アクティビティと SendReply アクティビティは、アクティビティとしては 2 つ存在していますが、前述で説明したように、Request-Reply 型の 1 つの処理 (Operation1) をあらわしています。SendReply アクティビティの [Request] 欄に設定されている「Receive」の文字列によって、上図の「Receive」という名前を持った Receive アクティビティと関連付けがおこなわれています。

Note: ここでは、ReceiveAndSendReply を使用して、Receive アクティビティと SendReply アクティビティを同時に挿入しましたが、それぞれを 1 つずつ挿入することも可能です。この方法については、10 行でズバリ !! ワークフローサービスにおける状態の維持 (Correlation の使用) (C#) を参考にしてください。

単一のアクティビティを呼び出して終了するだけの単純なワークフロー サービスの場合には問題になりませんが、ワークフロー サービスでは、通常、複数のクライアントから、複数個のワークフロー インスタンス (実行される個々のワークフロー) が呼び出される (起動される) ため、ワークフローの中の各アクティビティを呼び出して実行する際に、どのクライアントが、どのワークフロー インスタンスと対話しているか管理しておく必要があります。このための仕組みを Correlation と呼び、図 4 の Receive アクティビティと SendReply アクティビティでも、この関連付け (Correlation) の設定が必要です。

まず、Sequence アクティビティを選択して、[変数] をクリックすると、下図 (図 5) のように、この Correlation を扱うための CorrelationHandle 型の変数 (__handle1) が設定されています。

図 5. CorrelationHandle 変数

また、Receive アクティビティをクリックし、プロパティ ウィンドウの [CorrelationInitializer] 欄の右の [...] ボタンをクリックすると、下図 (図 6) のように、上記の __handle1 が、Request-Reply correlation initializer によって初期化されているのがわかります。

図 6. CorrelationHandle の初期化

この Correlation の初期化の設定によって、このサービスに接続しているクライアントから Receive アクティビティと SendReply アクティビティの 2 つのアクティビティを処理する際に、各クライアントが使用しているワークフロー インスタンスと矛盾なく対話 (クライアント インスタンスとワークフロー インスタンスが 1 対 1 で対話) することが可能になります。

今回は、単一の Receive アクティビティ、SendReply アクティビティ (1 組) を挿入することで、Visual Studio がこれらの設定を自動でおこなってくれていますが、複数個の Request-Reply 処理を挿入する場合などには、上記のように Correlation の設定を確認して、正しい設定をおこなうようにしてください。

なお、ここでは、Request-Reply Correlation の説明をおこないましたが、Correlation の詳細については、10 行でズバリ !! ワークフローサービスにおける状態の維持 (Correlation の使用) (C#) で、さらに詳しく説明します。

ページのトップへ


5. オペレーション名と、引数、返り値を設定する

「作成するアプリケーションの概要」(前述) で説明したように、今回、ユーザー Id (UserId) を渡して、カートの情報 (CartData) を取得する簡単なサービスを作成しますが、このカートを取得するオペレーション (メソッド) の名前を 「StartPurchase」とします。このため、Receive アクティビティの [OperationName] 欄に、下図の通り、「StartPurchase」の値を設定します。

図 7. OperationName の設定

今回、この StartPurchase メソッドの入力引数としてユーザー Id を渡すため、このユーザー Id を受け取るための変数をワークフローに作成します。Sequence アクティビティを選択して [変数] をクリックし、下図 (図 8) の通り、文字列型の変数 UserId を作成します。

図 8. UserId 変数の作成

Receive アクティビティの [Content] 欄の [定義...] (上図参照) をクリックすると、このオペレーションで受け取る引数を設定するための画面 (図 9) が表示されます。今回は、引数として取得した内容を上記の UserId の文字列型 (String 型) の変数に設定するため、下図のように、メッセージ データを「UserId」、メッセージ型を「String」に設定します。

図 9. オペレーションの入力引数の定義

つぎに、このオペレーションの返り値として、カート Id (CartId)、ユーザー Id (UserId)、現在の合計金額 (TotalCost) を含んだカート情報 (CartData) を返します。

まず、この CartData クラスを作成するため、ソリューション エクスプローラーのプロジェクトをマウスで右クリックして、[追加] - [新しい項目] メニューを選択します。表示される画面 (図 10) で [クラス] を選択し、[名前] 欄に、「CartData.cs」と入力して [追加] ボタンを押すと、CartData.cs クラスが作成されます。

図 10. クラスの作成

Note: ここでは、サンプルとして、ワークフロー サービスのプロジェクトにクラスを追加しましたが、このようなプログラム コードを含んだクラスは、ワークフローとは別のプロジェクトとして作成し、このプロジェクト内に参照追加をおこなって使用すると良いでしょう。

作成されたクラス ファイル (CartData.cs) に、以下の通りコードを記述します。(ここで使用している DataContract、DataMember については、10 行でズバリ !! サービスの作成 (WCF) (C#) を参照してください。)

C#
. . . 
using System.Runtime.Serialization;

. . .

[DataContract(Namespace = "")]
public class CartData
{
    [DataMember]
    public Guid CartId;
    [DataMember]
    public string UserId;
    [DataMember]
    public int TotalCost;
}
 

いったんリビルドをおこないます。

デザイナーに戻って [変数] をクリックし、「CartInfo」という名前の新しい変数を作成して、[変数の型] 欄で、[型の参照...] を選択します。(図 11)

図 11. CartInfo 変数の作成

型の検索をおこなうための画面が表示されるため、この上部に「CartData」と入力して、上記で作成した CartData 型を検索します (図 12)。この画面で、検索された「CartData」を選択して [OK] ボタンを押すと、図 11で、CartData 型が設定されます。

図 12. CartData 型の検索

デザイナー上で、SendReply アクティビティ (図 7 の「SendReplyToReceive」) の [Content] 欄の [定義...] をクリックし、表示される画面で、[メッセージ データ] に「CartInfo」と入力して、[メッセージ型] として CartData 型を選択して、[OK] ボタンを押します。

図 13. SendReply の返り値の設定

これで、入力引数 (UserId) と返り値 (CartData) の設定が完了しました。

ページのトップへ


6. 処理を作成する

このサービスの処理 (ロジック) をワークフローとして作成します。

今回は、返す CartData として、CartId に新しい Guid を設定し、UserId に引数で受け取った UserId をそのまま設定し、TotalCost に 0 (円) を設定します。

ツール ボックスから、Assign アクティビティをドラッグ・アンド・ドロップして、Receive アクティビティと SendReply アクティビティの間に挿入します。(下図)

図 14. Assign アクティビティの挿入

上図の Assign アクティビティの左辺に「CartInfo」と入力し、右辺に以下の VB 式を設定します。

C#
New CartData With {.CartId = Guid.NewGuid(), .UserId = UserId, .TotalCost = 0}
 

さいごに、最初の Receive アクティビティが呼ばれた際に、ワークフロー インスタンスを自動的に作成するように設定します。このため、Receive アクティビティを選択し、プロパティ ウィンドウの [CanCreateInstance] 欄のチェックをオンにします。(図 15)

図 15. CanCreateInstance の設定

プロジェクトのビルドをおこなって、ワークフロー サービスの作成は完了です。

ページのトップへ


7. サービスの名前と構成を設定する

作成されたワークフロー サービスは、通常の WCF サービスのように、Web.config (下記のコードを参照) を使用して、バインディング、ビヘイビアなどのサービスの振る舞いを変更することができます。

Note: ワークフロー サービスでは、10 行でズバリ !! ワークフローの状態の保存 (永続化) (C#) で説明したワークフローの永続化の処理なども、Web.config を記述して設定できます。(10 行でズバリ !! ワークフローの状態の保存 (永続化) (C#) で説明したように、プログラム コードを記述する必要はありません。)

また、ダウンロード センターから入手可能な Windows Server AppFabric を使用すると、こうした Web.config への永続化の設定などを UI (管理画面) を使って設定することができます。

ここで注意すべきは、ワークフローに設定されているサービスの名前と構成です。デザイナー上で Service1.xamlx をクリックすると、プロパティ ウィンドウに、下図の通り [ConfigurationName] が表示されます。

図 16. ワークフロー サービスの属性

Visual Studio が既定で作成する構成 (.config) では、下記の Web.config の通り、<service /> 要素が省略されていますが (サービス構成 (.config) の省略については、10 行でズバリ !! サービスの起動 (WCF のホスティング) (C#) を参照してください)、Web.config の <service /> 要素を記述した場合には、上記の ConfigurationName とこの <service /> 要素の name 属性の値が一致していなければならないので注意してください。(ここでは、特に変更はおこないません。)

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.web>
    <compilation debug="true" targetFramework="4.0" />
  </system.web>
  <system.serviceModel>
    <behaviors>
      <serviceBehaviors>
        <behavior>
          <serviceMetadata httpGetEnabled="true"/>
          <serviceDebug includeExceptionDetailInFaults="false"/>
        </behavior>
      </serviceBehaviors>
    </behaviors>
  </system.serviceModel>
  <system.webServer>
    <modules runAllManagedModulesForAllRequests="true"/>
  </system.webServer>
</configuration>

また、Web.config にサービスの contract を記述した場合にも (これも上記の通り、既定では省略されています)、下図のオペレーションの ServiceContractName と一致していなければならないので注意してください。

図 17. ワークフロー サービスの属性

今回は、こうした構成や名前の変更はおこなわず、既定の設定をそのまま使用します。

ページのトップへ


8. サービスを配置する

サービスは、[F5] ボタンを押してデバッグ用に起動できますが、今回は、IIS (Internet Information Services) 上に配置をおこないましょう。

Note: ここでは、IIS のバージョン 7.0 以降を使用した手順について説明します。

まず、IIS で使用するアプリケーション プールが .NET Framework 4 を使用できるように設定変更します。[コントロール パネル] で [管理ツール] を選択し、[インターネット インフォメーション サービス (IIS) マネージャ] を選択して、IIS マネージャを起動します。

図 18. インターネット インフォメーション サービス (IIS) マネージャ

左のナビゲーションの [アプリケーション プール] をクリックし、「DefaultAppPool」をクリックして、右のペインの [基本設定. . .] をクリックします。すると、アプリケーション プールの設定をおこなう画面 (図 19) が表示されるため、この画面で、[.Net Framework バージョン] として下図の通り .NET Framework 4 を選択し、[OK] ボタンを押します。

図 19. アプリケーション プールの .NET Framework バージョンの変更

Note: もし、既存の .NET Framework 2.0 の処理 (ASP.NET アプリケーションなど) も同時に使用しなければならない場合には、アプリケーション プールを新規作成して、その新規作成されたアプリケーション プールの .NET Framework バージョンを上記の通り変更し、追加するアプリケーション (後述) で、この作成したアプリケーション プールを使用するように設定します。

つぎに、上記で作成したサービス (アプリケーション) を IIS に配置します。配置では、サービス (アプリケーション) のディレクトリを IIS 上に公開する方法と、パッケージ ファイル (.zip ファイル) としてパッケージ化してこのファイルを IIS にインポートする方法の 2 種類の展開方法がありますが、今回は、前者の方法で展開をおこないましょう。

インターネット インフォメーション サービス (IIS) マネージャ (図 18) で、左のナビゲーションの「Default Web Site」をマウスで右クリックし、[アプリケーションの追加] メニューを選択します。表示される [アプリケーションの追加] 画面 (図 20) で、[エイリアス] を適当に入力し、[物理パス] として、前述で作成したサービスが保存されているディレクトリを設定します。(下図で、アプリケーション プールとして、上記の「DefaulAppPool」が設定されている点にも注意してください。)

図 20. アプリケーションの追加

以上で、作成したサービス アプリケーションが IIS 上に公開されました。

ページのトップへ


9. 動作を確認する (クライアントの作成)

では、配置されたサービスを使用してみましょう。

このサービスは、通常の WCF サービスと同様に、コンソール アプリケーションや Windows アプリケーション (WPF アプリケーション) などから使用できますが、今回は、ワークフロー コンソール アプリケーションから、このワークフロー サービスを使用してみましょう。(ワークフローの作成手順の詳細はここでは述べませんが、詳細は 10 行でズバリ !! ワークフローの作成 (WF) (C#) を参照してください。)

まず、ワークフロー コンソール アプリケーションのプロジェクトを新規作成します。

図 21. ワークフロー コンソール アプリケーション (クライアント) の作成

ソリューション エクスプローラーで、プロジェクトをマウスで右クリックして、[サービス参照の追加...] メニューを選択すると、[サービス参照の追加] 画面 (下図) が表示されます。この画面に、アドレスとして、上記で配置したサービスの .xamlx ファイルの URL を入力して、[OK] ボタンを押します。

図 22. サービス参照の追加

いったん、プロジェクトのビルドをおこない、Workflow1.xaml を表示すると、下図 (図 23) のように、公開されているワークフロー サービスのオペレーション (前述で作成した StartPurchase オペレーション) がアクティビティとして表示されます。

図 23. アクティビティとして挿入されたオペレーション

Sequence アクティビティをドラッグ・アンド・ドロップして挿入し、[変数] をクリックして、このアクティビティに渡す引数 (UserId) と返り値 (CartInfo) を図 24 のように変数として作成します。

図 24. クライアント側の変数の作成

あとは、いつものように、ワークフローの作成をおこなっていきます。(詳細は 10 行でズバリ !! ワークフローの作成 (WF) (C#) を参照してください。)

今回は、下図の通り、UserId に「demo001」を設定してワークフロー サービス (StartPurchase オペレーション) を呼び出し、取得した結果 (上記の CartInfo 変数に結果が入ります) のうち、CartId の値をコンソールに出力しています。(コンソールには、ワークフロー サービスで作成された GUID が表示されます。)

図 25. クライアント側のワークフロー

Note: ここでは、サービス参照の追加をおこなってワークフローどうしを連携させていますが、上述した Send アクティビティ、ReceiveReply アクティビティを使って、ワークフロー サービスを呼び出すこともできます。

実際、ここで使用した StartPurchase アクティビティ自体も、実は、この Send アクティビティと ReceiveReply アクティビティを呼び出す Sequence アクティビティとして実装されています。

 


Code Recipe .NET Framework デベロッパー センター

ページのトップへ