方法: ワークフローを実行する

このトピックでは、Windows Workflow Foundation チュートリアル入門の続きと、ワークフロー ホストを作成して、前の「 How to: Create a Workflow 」で定義したワークフローを実行する方法について説明します。

注意

チュートリアル入門の各トピックは、前のトピックに応じて異なります。 このトピックを完了する前に、「 How to: Create an Activity 」および「 How to: Create a Workflow」を完了する必要があります。

ワークフロー ホスト プロジェクトを作成するには

  1. Visual Studio 2012 を使用して、前の「方法: アクティビティを作成する」トピックのソリューションを開きます。

  2. ソリューション エクスプローラーWF45GettingStartedTutorial ソリューションを右クリックし、 [追加]をポイントして、 [新しいプロジェクト]をクリックします。

    ヒント

    [ソリューション エクスプローラー] ウィンドウが表示されていない場合は、[表示] メニューから [ソリューション エクスプローラー] を選択します。

  3. [インストール済み] ノードで、 [Visual C#][ワークフロー] (または [Visual Basic][ワークフロー]) の順に選択します。

    注意

    Visual Studio でのプライマリ言語の構成によっては、[Visual C#] または [Visual Basic] ノードが [インストール] ノードの [他の言語] ノードの下になる場合があります。

    [.NET Framework バージョン] ドロップダウン リストで [.NET Framework 4.5] が選択されていることを確認します。 [ワークフロー] の一覧から [ワークフロー コンソール アプリケーション] を選択します。 NumberGuessWorkflowHost [名前] ボックスに「 」と入力し、 [OK]をクリックします。 これで、基本的なワークフロー ホスティングをサポートする、基本ワークフロー アプリケーションが作成されます。 この基本的なホスティング コードを変更し、ワークフロー アプリケーションの実行に使用します。

  4. ソリューション エクスプローラー で新しく追加した NumberGuessWorkflowHost プロジェクトを右クリックし、 [参照の追加]をクリックします。 [参照の追加] の一覧から [ソリューション] を選択し、 NumberGuessWorkflowActivitiesの横にあるチェック ボックスをオンにして、 [OK]をクリックします。

  5. ソリューション エクスプローラーWorkflow1.xaml を右クリックし、 [削除]をクリックします。 [OK] をクリックして確定します。

ワークフロー ホスティング コードを変更するには

  1. ソリューション エクスプローラー で、 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

    前の「ワークフローの作成方法」手順で完了したワークフローに応じて、これらの例のWorkflow1FlowchartNumberGuessWorkflowSequentialNumberGuessWorkflow、または 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 が設定され、ホスト アプリケーションが完了します。

ワークフローの入力引数を設定するには

  1. Program.cs または Module1.vb の先頭にある既存の using ステートメントまたは Imports ステートメントの下に、次のステートメントを追加します。

  2. 新しい WorkflowApplication を作成するコード行を、作成時にワークフローにパラメーターの辞書を作成して渡す次のコードに置き換えます。

    注意

    前の「 Workflow1 」の手順で完了したワークフローに応じて、これらの例の FlowchartNumberGuessWorkflowをポイントして、 SequentialNumberGuessWorkflowStateMachineNumberGuessWorkflow、または 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 は、ランダムに生成される数値の上限を決定するためにワークフローによって使用されます。

ワークフローの出力引数を取得するには

  1. 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
    

ブックマークを再開するには

  1. Main メソッドの上部にある既存の AutoResetEvent 宣言の直後に、次のコードを追加します。

    AutoResetEvent idleEvent = new AutoResetEvent(false);
    
    Dim idleEvent As New AutoResetEvent(False)
    
  2. Idle にある既存の 3 つのワークフロー ライフサイクル ハンドラーの直後に、次の Mainハンドラーを追加します。

        Idle = delegate (WorkflowApplicationIdleEventArgs e)
        {
            idleEvent.Set();
        }
    };
    
    wfApp.Idle =
        Sub(e As WorkflowApplicationIdleEventArgs)
            idleEvent.Set()
        End Sub
    

    このハンドラーは、次の推定値を待機してワークフローがアイドル状態になるたびに呼び出され、idleAction AutoResetEvent が設定されます。 次の手順のコードでは、 idleEventsyncEvent を使用して、ワークフローが次の推定値を待機しているのか、完了しているのかを判断します。

    注意

    この例では、ホスト アプリケーションは Completed および Idle ハンドラーの自動リセット イベントを使用して、ホスト アプリケーションとワークフローの進行状況を同期させます。 ブックマークを再開する前にワークフローがアイドル状態になるのをブロックして待機する必要はありませんが、この例では同期イベントが必要であるため、ホストはワークフローが完了しているのか、さらにユーザーの入力を待っているのかを Bookmarkを使用して把握します。 詳細については、「ブックマーク」を参照してください。

  3. 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
    

アプリケーションをビルドして実行するには

  1. ソリューション エクスプローラーNumberGuessWorkflowHost を右クリックして [スタートアップ プロジェクトに設定]を選択します。

  2. Ctrl キーを押しながら F5 キーを押してアプリケーションをビルドし、実行します。 できるだけ早い順番の数を推測します。

    他のスタイルのワークフローのいずれかでアプリケーションを試すには、目的のワークフローのスタイルに応じて、 Workflow1 を作成するコード内の WorkflowApplication を、 FlowchartNumberGuessWorkflowSequentialNumberGuessWorkflow、または 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をポイントして、 SequentialNumberGuessWorkflowStateMachineNumberGuessWorkflow、または 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

関連項目