方法: ワークフローを実行する
このトピックでは、Windows Workflow Foundation チュートリアル入門の続きと、ワークフロー ホストを作成して、前の「 How to: Create a Workflow 」で定義したワークフローを実行する方法について説明します。
注意
チュートリアル入門の各トピックは、前のトピックに応じて異なります。 このトピックを完了する前に、「 How to: Create an Activity 」および「 How to: Create a Workflow」を完了する必要があります。
ワークフロー ホスト プロジェクトを作成するには
Visual Studio 2012 を使用して、前の「方法: アクティビティを作成する」トピックのソリューションを開きます。
ソリューション エクスプローラー で WF45GettingStartedTutorial ソリューションを右クリックし、 [追加]をポイントして、 [新しいプロジェクト]をクリックします。
ヒント
[ソリューション エクスプローラー] ウィンドウが表示されていない場合は、[表示] メニューから [ソリューション エクスプローラー] を選択します。
[インストール済み] ノードで、 [Visual C#]、 [ワークフロー] (または [Visual Basic]、 [ワークフロー]) の順に選択します。
注意
Visual Studio でのプライマリ言語の構成によっては、[Visual C#] または [Visual Basic] ノードが [インストール] ノードの [他の言語] ノードの下になる場合があります。
[.NET Framework バージョン] ドロップダウン リストで [.NET Framework 4.5] が選択されていることを確認します。 [ワークフロー] の一覧から [ワークフロー コンソール アプリケーション] を選択します。
NumberGuessWorkflowHost
[名前] ボックスに「 」と入力し、 [OK]をクリックします。 これで、基本的なワークフロー ホスティングをサポートする、基本ワークフロー アプリケーションが作成されます。 この基本的なホスティング コードを変更し、ワークフロー アプリケーションの実行に使用します。ソリューション エクスプローラー で新しく追加した NumberGuessWorkflowHost プロジェクトを右クリックし、 [参照の追加]をクリックします。 [参照の追加] の一覧から [ソリューション] を選択し、 NumberGuessWorkflowActivitiesの横にあるチェック ボックスをオンにして、 [OK]をクリックします。
ソリューション エクスプローラー で Workflow1.xaml を右クリックし、 [削除]をクリックします。 [OK] をクリックして確定します。
ワークフロー ホスティング コードを変更するには
ソリューション エクスプローラー で、 Program.cs または Module1.vb をダブルクリックしてコードを表示します。
ヒント
[ソリューション エクスプローラー] ウィンドウが表示されていない場合は、[表示] メニューから [ソリューション エクスプローラー] を選択します。
このプロジェクトは ワークフロー コンソール アプリケーション テンプレートを使用して作成されたため、 Program.cs または Module1.vb には、次のようなワークフローの基本的なホスティング コードが含まれます。
' Create and cache the workflow definition. Dim workflow1 As Activity = New Workflow1() WorkflowInvoker.Invoke(workflow1)
// Create and cache the workflow definition. Activity workflow1 = new Workflow1(); WorkflowInvoker.Invoke(workflow1);
この生成されたホスト コードでは WorkflowInvokerを使用します。 WorkflowInvoker は、メソッド呼び出しのようにワークフローを呼び出す簡単な方法を提供し、永続化を使用しないワークフローのみに使用できます。 WorkflowApplication は、ライフ サイクル イベントの通知、実行制御、ブックマークの再開、および永続化を含むワークフローを実行するための豊富なモデルを提供します。 次の例ではブックマークを使用し、ワークフローのホスティングには WorkflowApplication を使用します。
using
Program.cs または Module1.vb の先頭にある既存の using ステートメントまたは Imports ステートメントの下に、次の ステートメントまたは Imports ステートメントを追加します。Imports NumberGuessWorkflowActivities Imports System.Threading
using NumberGuessWorkflowActivities; using System.Threading;
WorkflowInvoker を使用するコード行を次の WorkflowApplication の基本的なホスティング コードに置き換えます。 このサンプル ホスティング コードでは、ワークフローをホストして呼び出すための基本的な手順を示します。ただし、このトピックのワークフローを正しく実行するための機能はまだありません。 次の手順では、アプリケーションが完了するまでにこの基本的なコードを変更して機能を追加します。
Note
前の「ワークフローの作成方法」手順で完了したワークフローに応じて、これらの例の
Workflow1
をFlowchartNumberGuessWorkflow
、SequentialNumberGuessWorkflow
、またはStateMachineNumberGuessWorkflow
で、置き換えます。Workflow1
を置き換えないと、ワークフローをビルドまたは実行しようとするときにビルド エラーが発生します。AutoResetEvent syncEvent = new AutoResetEvent(false); WorkflowApplication wfApp = new WorkflowApplication(_wf); wfApp.Completed = delegate (WorkflowApplicationCompletedEventArgs e) { syncEvent.Set(); }; wfApp.Aborted = delegate (WorkflowApplicationAbortedEventArgs e) { Console.WriteLine(e.Reason); syncEvent.Set(); }; wfApp.OnUnhandledException = delegate (WorkflowApplicationUnhandledExceptionEventArgs e) { Console.WriteLine(e.UnhandledException.ToString()); return UnhandledExceptionAction.Terminate; }; wfApp.Run(); syncEvent.WaitOne();
Dim syncEvent As New AutoResetEvent(False) Dim wfApp As New WorkflowApplication(New Workflow1()) wfApp.Completed = Sub(e As WorkflowApplicationCompletedEventArgs) syncEvent.Set() End Sub wfApp.Aborted = Sub(e As WorkflowApplicationAbortedEventArgs) Console.WriteLine(e.Reason) syncEvent.Set() End Sub wfApp.OnUnhandledException = Function(e As WorkflowApplicationUnhandledExceptionEventArgs) Console.WriteLine(e.UnhandledException) Return UnhandledExceptionAction.Terminate End Function wfApp.Run() syncEvent.WaitOne()
このコードでは WorkflowApplicationを作成し、3 つのワークフローのライフサイクル イベントに定期受信し、 Runを呼び出してワークフローを開始し、そのワークフローが完了するまで待機します。 ワークフローが完了すると AutoResetEvent が設定され、ホスト アプリケーションが完了します。
ワークフローの入力引数を設定するには
Program.cs または Module1.vb の先頭にある既存の
using
ステートメントまたはImports
ステートメントの下に、次のステートメントを追加します。新しい WorkflowApplication を作成するコード行を、作成時にワークフローにパラメーターの辞書を作成して渡す次のコードに置き換えます。
注意
前の「
Workflow1
」の手順で完了したワークフローに応じて、これらの例のFlowchartNumberGuessWorkflow
をポイントして、SequentialNumberGuessWorkflow
、StateMachineNumberGuessWorkflow
、または How to: Create a Workflow に置き換えます。Workflow1
を置き換えないと、ワークフローをビルドまたは実行しようとするときにビルド エラーが発生します。var inputs = new Dictionary<string, object>() { { "MaxNumber", 100 } }; WorkflowApplication wfApp = new(_wf, inputs) {
Dim inputs As New Dictionary(Of String, Object) inputs.Add("MaxNumber", 100) Dim wfApp As New WorkflowApplication(New Workflow1(), inputs)
この辞書には、
MaxNumber
というキーを持つ 1 つの要素が含まれます。 入力辞書のキーは、ワークフローのルート アクティビティの入力引数に対応します。MaxNumber
は、ランダムに生成される数値の上限を決定するためにワークフローによって使用されます。
ワークフローの出力引数を取得するには
Completed ハンドラーを変更して、ワークフローが使用する順番の数を取得して表示します。
Completed = delegate (WorkflowApplicationCompletedEventArgs e) { int Turns = Convert.ToInt32(e.Outputs["Turns"]); Console.WriteLine("Congratulations, you guessed the number in {0} turns.", Turns); syncEvent.Set(); },
wfApp.Completed = Sub(e As WorkflowApplicationCompletedEventArgs) Dim Turns As Integer = Convert.ToInt32(e.Outputs("Turns")) Console.WriteLine("Congratulations, you guessed the number in {0} turns.", Turns) syncEvent.Set() End Sub
ブックマークを再開するには
Main
メソッドの上部にある既存の AutoResetEvent 宣言の直後に、次のコードを追加します。AutoResetEvent idleEvent = new AutoResetEvent(false);
Dim idleEvent As New AutoResetEvent(False)
Idle にある既存の 3 つのワークフロー ライフサイクル ハンドラーの直後に、次の
Main
ハンドラーを追加します。Idle = delegate (WorkflowApplicationIdleEventArgs e) { idleEvent.Set(); } };
wfApp.Idle = Sub(e As WorkflowApplicationIdleEventArgs) idleEvent.Set() End Sub
このハンドラーは、次の推定値を待機してワークフローがアイドル状態になるたびに呼び出され、
idleAction
AutoResetEvent が設定されます。 次の手順のコードでは、idleEvent
とsyncEvent
を使用して、ワークフローが次の推定値を待機しているのか、完了しているのかを判断します。WaitOne
への呼び出しを削除して、ユーザーからの入力を収集して Bookmarkを再開するためのコードに置き換えます。次のコード行を削除します。
syncEvent.WaitOne();
syncEvent.WaitOne()
これを次の例に置き換えます。
// Loop until the workflow completes. WaitHandle[] handles = new WaitHandle[] { syncEvent, idleEvent }; while (WaitHandle.WaitAny(handles) != 0) { // Gather the user input and resume the bookmark. bool validEntry = false; while (!validEntry) { if (!Int32.TryParse(Console.ReadLine(), out int Guess)) { Console.WriteLine("Please enter an integer."); } else { validEntry = true; wfApp.ResumeBookmark("EnterGuess", Guess); } } }
' Loop until the workflow completes. Dim waitHandles As WaitHandle() = New WaitHandle() {syncEvent, idleEvent} Do While WaitHandle.WaitAny(waitHandles) <> 0 'Gather the user input and resume the bookmark. Dim validEntry As Boolean = False Do While validEntry = False Dim Guess As Integer If Int32.TryParse(Console.ReadLine(), Guess) = False Then Console.WriteLine("Please enter an integer.") Else validEntry = True wfApp.ResumeBookmark("EnterGuess", Guess) End If Loop Loop
アプリケーションをビルドして実行するには
ソリューション エクスプローラー で NumberGuessWorkflowHost を右クリックして [スタートアップ プロジェクトに設定]を選択します。
Ctrl キーを押しながら F5 キーを押してアプリケーションをビルドし、実行します。 できるだけ早い順番の数を推測します。
他のスタイルのワークフローのいずれかでアプリケーションを試すには、目的のワークフローのスタイルに応じて、
Workflow1
を作成するコード内の WorkflowApplication を、FlowchartNumberGuessWorkflow
、SequentialNumberGuessWorkflow
、またはStateMachineNumberGuessWorkflow
に置き換えます。var inputs = new Dictionary<string, object>() { { "MaxNumber", 100 } }; WorkflowApplication wfApp = new(_wf, inputs) {
Dim inputs As New Dictionary(Of String, Object) inputs.Add("MaxNumber", 100) Dim wfApp As New WorkflowApplication(New Workflow1(), inputs)
ワークフロー アプリケーションに永続化を追加する方法については、次のトピック「 How to: Create and Run a Long Running Workflow」を参照してください。
例
次の例では、 Main
メソッドの完全なコードの一覧を示します。
注意
前の「 Workflow1
」の手順で完了したワークフローに応じて、これらの例の FlowchartNumberGuessWorkflow
をポイントして、 SequentialNumberGuessWorkflow
、 StateMachineNumberGuessWorkflow
、または How to: Create a Workflow に置き換えます。 Workflow1
を置き換えないと、ワークフローをビルドまたは実行しようとするときにビルド エラーが発生します。
static void Main(string[] args)
{
AutoResetEvent syncEvent = new AutoResetEvent(false);
AutoResetEvent idleEvent = new AutoResetEvent(false);
var inputs = new Dictionary<string, object>() { { "MaxNumber", 100 } };
WorkflowApplication wfApp = new(_wf, inputs)
{
Completed = delegate (WorkflowApplicationCompletedEventArgs e)
{
int Turns = Convert.ToInt32(e.Outputs["Turns"]);
Console.WriteLine("Congratulations, you guessed the number in {0} turns.", Turns);
syncEvent.Set();
},
Aborted = delegate (WorkflowApplicationAbortedEventArgs e)
{
Console.WriteLine(e.Reason);
syncEvent.Set();
},
OnUnhandledException = delegate (WorkflowApplicationUnhandledExceptionEventArgs e)
{
Console.WriteLine(e.UnhandledException.ToString());
return UnhandledExceptionAction.Terminate;
},
Idle = delegate (WorkflowApplicationIdleEventArgs e)
{
idleEvent.Set();
}
};
wfApp.Run();
// Loop until the workflow completes.
WaitHandle[] handles = new WaitHandle[] { syncEvent, idleEvent };
while (WaitHandle.WaitAny(handles) != 0)
{
// Gather the user input and resume the bookmark.
bool validEntry = false;
while (!validEntry)
{
if (!Int32.TryParse(Console.ReadLine(), out int Guess))
{
Console.WriteLine("Please enter an integer.");
}
else
{
validEntry = true;
wfApp.ResumeBookmark("EnterGuess", Guess);
}
}
}
}
Sub Main()
Dim syncEvent As New AutoResetEvent(False)
Dim idleEvent As New AutoResetEvent(False)
Dim inputs As New Dictionary(Of String, Object)
inputs.Add("MaxNumber", 100)
Dim wfApp As New WorkflowApplication(New Workflow1(), inputs)
wfApp.Completed =
Sub(e As WorkflowApplicationCompletedEventArgs)
Dim Turns As Integer = Convert.ToInt32(e.Outputs("Turns"))
Console.WriteLine("Congratulations, you guessed the number in {0} turns.", Turns)
syncEvent.Set()
End Sub
wfApp.Aborted =
Sub(e As WorkflowApplicationAbortedEventArgs)
Console.WriteLine(e.Reason)
syncEvent.Set()
End Sub
wfApp.OnUnhandledException =
Function(e As WorkflowApplicationUnhandledExceptionEventArgs)
Console.WriteLine(e.UnhandledException)
Return UnhandledExceptionAction.Terminate
End Function
wfApp.Idle =
Sub(e As WorkflowApplicationIdleEventArgs)
idleEvent.Set()
End Sub
wfApp.Run()
' Loop until the workflow completes.
Dim waitHandles As WaitHandle() = New WaitHandle() {syncEvent, idleEvent}
Do While WaitHandle.WaitAny(waitHandles) <> 0
'Gather the user input and resume the bookmark.
Dim validEntry As Boolean = False
Do While validEntry = False
Dim Guess As Integer
If Int32.TryParse(Console.ReadLine(), Guess) = False Then
Console.WriteLine("Please enter an integer.")
Else
validEntry = True
wfApp.ResumeBookmark("EnterGuess", Guess)
End If
Loop
Loop
End Sub
関連項目
.NET