実行時間の長いワークフロー サービスを作成する
この記事では、長時間実行できる実行時間の長いワークフロー サービスを作成する方法について説明します。 ワークフローでは、追加情報を待つ間アイドル状態になることがあります。 アイドル状態になると、ワークフローは SQL データベースに永続化され、メモリから削除されます。 追加情報が使用可能になると、ワークフロー インスタンスがメモリに読み込み直されて、実行を継続します。
このシナリオでは、非常に簡略化された注文システムを実装します。 クライアントは、最初のメッセージをワークフロー サービスに送信して注文を開始します。 ワークフロー サービスは、注文 ID をクライアントに返します。 この時点で、ワークフロー サービスは、クライアントからの別のメッセージを待機しており、アイドル状態に入って、SQL Server データベースに永続化されます。 クライアントが次のメッセージを送信して項目を注文すると、ワークフロー サービスはメモリに読み込み直されて、注文の処理を終了します。
次のコード例では、項目が注文に追加されたことを示す文字列を返します。 このコード例は、テクノロジの実際の適用を意図するものではなく、実行時間の長いワークフロー サービスを示す簡単な例です。
前提条件
このチュートリアルを使用するには、次のソフトウェアがインストールされている必要があります。
- Microsoft SQL Server 2008
- Visual Studio 2012
- Microsoft .NET Framework 4.6.1
また、WCF と Visual Studio 2012 に精通し、プロジェクト/ソリューションの作成方法を理解している必要があります。
SQL データベースを設定する
ワークフロー サービス インスタンスが永続化されるようにするには、Microsoft SQL Server をインストールして、永続化ワークフロー インスタンスを保存するようにデータベースを設定する必要があります。 [スタート] ボタンをクリックし、 [すべてのプログラム] 、 [Microsoft SQL Server 2008] 、 [Microsoft SQL Management Studio] の順にクリックして Microsoft SQL Management Studio を実行します。
[接続] ボタンをクリックして SQL Server インスタンスにログオンします。
ツリー ビューで [データベース] を右クリックして [新しいデータベース] の順に選択し、
SQLPersistenceStore
という名前の新しいデータベースを作成します。SQLPersistenceStore データベースの C:\Windows\Microsoft.NET\Framework\v4.0\SQL\en ディレクトリにある SqlWorkflowInstanceStoreSchema.sql スクリプト ファイルを実行して、必要なデータベース スキーマを設定します。
SQLPersistenceStore データベースの C:\Windows\Microsoft.NET\Framework\v4.0\SQL\en ディレクトリにある SqlWorkflowInstanceStoreLogic.sql スクリプト ファイルを実行して、必要なデータベース ロジックを設定します。
Web ホスト ワークフロー サービスを作成する
空の Visual Studio 2012 ソリューションを作成し、
OrderProcessing
という名前を付けます。OrderService
という新しい WCF ワークフロー サービス アプリケーション プロジェクトをソリューションに追加します。プロジェクトのプロパティのダイアログで [Web] タブをクリックします。
[開始動作] の [ページを指定する] をクリックし、
Service1.xamlx
を指定します。[サーバー] の [ローカル IIS Web サーバーを使用する] を選択します。
警告
この設定を行うには、Visual Studio 2012 を管理者モードで実行する必要があります。
次の 2 つの手順で、ワークフロー サービス プロジェクトが IIS でホストされるように設定します。
Service1.xamlx
が開いていない場合は開き、既存の ReceiveRequest アクティビティと SendResponse アクティビティを削除します。[シーケンシャル サービス] アクティビティを選択し、 [変数] リンクをクリックします。そして、次の図に示されている変数を追加します。 こうするといくつかの変数が追加され、後でワークフロー サービスで使用されます。
Note
CorrelationHandle が [変数の型] ボックスにない場合は、ボックスから [型の参照] を選択します。 [型名] ボックスに「CorrelationHandle」と入力し、リスト ボックスから [CorrelationHandle] を選択して [OK] をクリックします。
ReceiveAndSendReply アクティビティ テンプレートをドラッグし、 [シーケンシャル サービス] アクティビティにドロップします。 このアクティビティのセットは、クライアントからメッセージを受信して、返信を送信します。
Receive アクティビティを選択し、次の図で強調表示されているプロパティを設定します。
DisplayName プロパティは、デザイナーに表示される Receive アクティビティの名前を設定します。 ServiceContractName プロパティと OperationName プロパティは、Receive アクティビティで実装されるサービス コントラクトおよび操作の名前を指定します。 ワークフロー サービスでのコントラクトの使用方法の詳細については、「ワークフロー内でのコントラクトの使用」を参照してください。
ReceiveStartOrder アクティビティの [定義] リンクをクリックし、次の図に示されているプロパティを設定します。 [パラメーター] オプション ボタンが選択され、
p_customerName
という名前のパラメーターがcustomerName
変数にバインドされていることに注目してください。 これにより、Receive アクティビティがいくつかのデータを受け取り、そのデータをローカル変数にバインドするように設定されます。SendReplyToReceive アクティビティを選択し、次の図で強調表示されているプロパティを設定します。
SendReplyToStartOrder アクティビティの [定義] リンクをクリックし、次の図に示されているプロパティを設定します。 [パラメーター] オプション ボタンが選択され、
p_orderId
という名前のパラメーターがorderId
変数にバインドされていることに注目してください。 この設定により、SendReplyToStartOrder アクティビティが型文字列の値を呼び出し元に返すように指定されます。Assign アクティビティをドラッグし、Receive アクティビティと SendReply アクティビティの間にドロップします。次の図に示されているようにプロパティを設定します。
これにより、新しい注文 ID が作成され、orderId 変数に値が配置されます。
ReplyToStartOrder アクティビティを選択します。 プロパティ ウィンドウで、CorrelationInitializers の省略記号ボタンをクリックします。 [初期化子の追加] リンクを選択し、[初期化子] テキスト ボックスに「
orderIdHandle
」と入力します。[関連付けの種類] として [クエリ関連付け初期化子] を選択し、[XPATH クエリ] ドロップダウン ボックスの p_orderId を選択します。 これらの設定を次の図に示します。 [OK] をクリックします。 これにより、クライアントとワークフロー サービスのこのインスタンス間の相関関係が初期化されます。 この注文 ID を含むメッセージが受信されると、ワークフロー サービスのこのインスタンスにルーティングされます。
別の ReceiveAndSendReply アクティビティをドラッグし、ワークフローの最後 (最初の Receive アクティビティと SendReply アクティビティを含む [シーケンス] の外側) にドロップします。 これで、クライアントで送信された 2 つ目のメッセージを受信し、それに応答します。
新しく追加された Receive アクティビティと SendReply アクティビティを含む [シーケンス] を選択し、 [変数] ボタンをクリックします。 次の図で強調表示されている変数を追加します。
また、
Sequence
スコープ内の [文字列] としてorderResult
を追加します。Receive アクティビティを選択し、次の図に示されているプロパティを設定します。
注意
必ず、ServiceContractName フィールドを
../IAddItem
で変更してください。ReceiveAddItem アクティビティの [定義] リンクをクリックし、次の図に示されているパラメーターを追加します。これにより、Receive アクティビティが、2 つのパラメーター、注文 ID、および注文されている項目の ID を受け取るように設定されます。
CorrelateOn の省略記号ボタンをクリックし、「
orderIdHandle
」を入力します。 [XPath クエリ] でドロップダウン矢印をクリックし、p_orderId
を選択します。 これにより、2 つ目の Receive アクティビティに相関関係が設定されます。 関連付けの詳細については、「関連付け」を参照してください。If アクティビティをドラッグし、ReceiveAddItem アクティビティの直後にドロップします。 このアクティビティは、if ステートメントと同様に動作します。
Condition プロパティを
itemId=="Zune HD" (itemId="Zune HD" for Visual Basic)
に設定します。Assign アクティビティを 1 つずつ、Then セクションと Else セクションにドラッグ アンド ドロップし、次の図に示されているように Assign アクティビティのプロパティを設定します。
条件が
true
である場合は、Then セクションが実行されます。 条件がfalse
である場合は、Else セクションが実行されます。SendReplyToReceive アクティビティを選択し、次の図で強調表示されている DisplayName プロパティを設定します。
SetReplyToAddItem アクティビティの [定義] リンクをクリックし、次の図に示されているように設定します。 これにより、SendReplyToAddItem アクティビティが
orderResult
変数に値を返すように設定されます。
web.config ファイルを開いて、次の要素を <behavior> セクションに追加し、ワークフロー永続化を有効にします。 (接続文字列を忘れずに完了してください)。
<sqlWorkflowInstanceStore connectionString="...;Asynchronous Processing=True" instanceEncodingOption="None" instanceCompletionAction="DeleteAll" instanceLockedExceptionAction="BasicRetry" hostLockRenewalPeriod="00:00:30" runnableInstancesDetectionPeriod="00:00:02" /> <workflowIdle timeToUnload="0"/>
ソリューションをビルドします。
クライアント アプリケーションを作成してワークフロー サービスを呼び出す
OrderClient
という新しいコンソール アプリケーション プロジェクトをソリューションに追加します。次のアセンブリへの参照を
OrderClient
プロジェクトに追加します。System.ServiceModel.dll
System.ServiceModel.Activities.dll
サービス参照をワークフロー サービスに追加し、
OrderService
を名前空間として指定します。クライアント プロジェクトの
Main()
メソッド内に次のコードを追加します。static void Main(string[] args) { // Send initial message to start the workflow service Console.WriteLine("Sending start message"); StartOrderClient startProxy = new StartOrderClient(); string orderId = startProxy.StartOrder("Kim Abercrombie"); // The workflow service is now waiting for the second message to be sent Console.WriteLine("Workflow service is idle..."); Console.WriteLine("Press [ENTER] to send an add item message to reactivate the workflow service..."); Console.ReadLine(); // Send the second message Console.WriteLine("Sending add item message"); AddItemClient addProxy = new AddItemClient(); AddItem item = new AddItem(); item.p_itemId = "Zune HD"; item.p_orderId = orderId; string orderResult = addProxy.AddItem(item); Console.WriteLine("Service returned: " + orderResult); }
ソリューションをビルドし、
OrderClient
アプリケーションを実行します。 クライアントに次のテキストが表示されます。Sending start messageWorkflow service is idle...Press [ENTER] to send an add item message to reactivate the workflow service...
ワークフロー サービスが永続化されていることを確認するには、 [スタート] メニューで [すべてのプログラム] 、 [Microsoft SQL Server 2008] 、 [SQL Server Management Studio] の順にクリックして SQL Server Management Studio を起動します。
- 左側のペインで [データベース] 、 [SQLPersistenceStore] 、 [ビュー] の順に展開します。System.Activities.DurableInstancing.Instances を右クリックし、 [上位 1000 行を選択] をクリックします。 [結果] ペインで、少なくとも 1 つのインスタンスが一覧に含まれていることを確認します。 実行中に例外が発生した場合は、前の実行のその他のインスタンスがある可能性があります。 既存の行を削除するには、System.Activities.DurableInstancing.Instances を右クリックし、 [上位 200 行を編集] をクリックし、 [実行] ボタンをクリックしたら、結果のペインのすべての行を選択し、 [削除] をクリックします。 データベースに表示されているインスタンスが、アプリケーションで作成されたインスタンスであることを確認するには、クライアントを実行する前に、Instances ビューが空であることを確認します。 クライアントが実行されると、クエリ ([上位 1000 行を選択]) を再実行し、新しいインスタンスが追加されていることを確認します。
Enter キーを押して、項目の追加メッセージをワークフロー サービスに送信します。 クライアントに次のテキストが表示されます。
Sending add item messageService returned: Item added to orderPress any key to continue . . .