How to: Run a Workflow

This topic applies to Windows Workflow Foundation 4 (WF4).

This topic is a continuation of the Windows Workflow Foundation Getting Started tutorial and discusses how to run the workflow defined in the previous How to: Create a Workflow topic.

Note

Each topic in the Getting Started tutorial depends on the previous topics. To complete this topic you must first complete How to: Create an Activity and How to: Create a Workflow.

Note

To view a video walkthrough of this topic or to download a completed version of the tutorial, see Windows Workflow Foundation (WF4) - Getting Started Tutorial.

To open the workflow host project

  1. Open the solution from the previous How to: Create a Workflow topic by using Visual Studio 2010.

  2. Double-click Program.cs or Module1.vb in Solution Explorer to display the code.

    Dd489463.Tip(en-us,VS.100).gifTip:
    If the Solution Explorer window is not displayed, select Solution Explorer from the View menu.

    Because this project was created by using the Workflow Console Application template, Program.cs or Module1.vb contains the following basic workflow hosting code.

    WorkflowInvoker.Invoke(New Workflow1())
    
    WorkflowInvoker.Invoke(new Workflow1());
    
    WorkflowInvoker.Invoke(new Workflow1());
    

    This generated hosting code uses WorkflowInvoker. WorkflowInvoker provides a simple way for invoking a workflow as if it were a method call and can be used only for workflows that do not use persistence. WorkflowApplication provides a richer model for executing workflows that includes notification of life-cycle events, execution control, bookmark resumption, and persistence. This example uses bookmarks and WorkflowApplication is used for hosting the workflow. Add the following using or Imports statement at the top of Program.cs or Module1.vb below the existing using or Imports statements.

    Imports System.Threading
    
    using System.Threading;
    
    using System.Threading;
    

    Replace the line of code that uses WorkflowInvoker with the following basic WorkflowApplication hosting code. This sample hosting code demonstrates the basic steps for hosting and invoking a workflow, but does not yet contain the functionality to successfully run the workflow from this topic. In the following steps, this basic code is modified and additional features are added until the application is complete.

    Note

    Please replace Workflow1 in these examples with FlowchartNumberGuessWorkflow, SequentialNumberGuessWorkflow, or StateMachineNumberGuessWorkflow, depending on which workflow you completed in the previous How to: Create a Workflow step.

    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()
    
    AutoResetEvent syncEvent = new AutoResetEvent(false);
    
    WorkflowApplication wfApp =
        new WorkflowApplication(new Workflow1());
    
    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();
    
    AutoResetEvent syncEvent = new AutoResetEvent(false);
    
    WorkflowApplication wfApp =
        new WorkflowApplication(new Workflow1());
    
    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();
    

    This code creates a WorkflowApplication, subscribes to three workflow life-cycle events, starts the workflow with a call to Run, and then waits for the workflow to complete. When the workflow completes, the AutoResetEvent is set and the host application completes.

To set input arguments of a workflow

  1. Add the following statement at the top of Program.cs or Module1.vb below the existing using or Imports statements.

    Imports System.Collections.Generic
    
    using System.Collections.Generic;
    
  2. Replace the line of code that creates the new WorkflowApplication with the following code that creates and passes a dictionary of parameters to the workflow when it is created.

    Note

    Please replace Workflow1 in these examples with FlowchartNumberGuessWorkflow, SequentialNumberGuessWorkflow, or StateMachineNumberGuessWorkflow, depending on which workflow you completed in the previous How to: Create a Workflow step.

    Dim inputs As New Dictionary(Of String, Object)
    inputs.Add("MaxNumber", 100)
    
    Dim wfApp As New WorkflowApplication(New Workflow1(), inputs)
    
    var wfparams = new Dictionary<string, object>() { { "MaxNumber", 100 } };
    
    WorkflowApplication wfApp =
        new WorkflowApplication(new Workflow1(), wfparams);
    
    var inputs = new Dictionary<string, object>() { { "MaxNumber", 100 } };
    
    WorkflowApplication wfApp =
        new WorkflowApplication(new Workflow1(), inputs);
    

    This dictionary contains one element with a key of MaxNumber. Keys in the input dictionary correspond to input arguments on the root activity of the workflow. MaxNumber is used by the workflow to determine the upper bound for the randomly generated number.

To retrieve output arguments of a workflow

  1. Modify the Completed handler to retrieve and display the number of turns used by the workflow.

    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.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 = delegate(WorkflowApplicationCompletedEventArgs e)
    {
        int Turns = Convert.ToInt32(e.Outputs["Turns"]);
        Console.WriteLine("Congratulations, you guessed the number in {0} turns.", Turns);
    
        syncEvent.Set();
    };
    

To resume a bookmark

  1. Add the following code at the top of the Main method just after the existing AutoResetEvent declaration.

    Dim idleEvent As New AutoResetEvent(False)
    
    AutoResetEvent idleEvent = new AutoResetEvent(false);
    
    AutoResetEvent idleEvent = new AutoResetEvent(false);
    
  2. Add the following Idle handler just below the existing three workflow life-cycle handlers in Main.

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

    Each time the workflow becomes idle waiting for the next guess, this handler is called and the idleAction AutoResetEvent is set. The code in the following step uses idleEvent and syncEvent to determine whether the workflow is waiting for the next guess or is complete.

    Note

    In this example, the host application uses auto-reset events in the Completed and Idle handlers to synchronize the host application with the progress of the workflow. It is not necessary to block and wait for the workflow to become idle before resuming a bookmark, but in this example the synchronization events are required so the host knows whether the workflow is complete or whether it is waiting on more user input by using the Bookmark. For more information, see Bookmarks.

  3. Remove the call to WaitOne, and replace it with code to gather input from the user and resume the Bookmark.

    Remove the following line of code.

    syncEvent.WaitOne()
    
    syncEvent.WaitOne();
    
    syncEvent.WaitOne();
    

    Replace it with the following example.

    ' 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
    
    // 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)
        {
            int Guess;
            if (!Int32.TryParse(Console.ReadLine(), out Guess))
            {
                Console.WriteLine("Please enter an integer.");
            }
            else
            {
                validEntry = true;
                wfApp.ResumeBookmark("EnterGuess", Guess);
            }
        }
    }
    
    // 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)
        {
            int Guess;
            if (!Int32.TryParse(Console.ReadLine(), out Guess))
            {
                Console.WriteLine("Please enter an integer.");
            }
            else
            {
                validEntry = true;
                wfApp.ResumeBookmark("EnterGuess", Guess);
            }
        }
    }
    

To build and run the application

  1. Right-click WorkflowConsoleApplication1 in Solution Explorer and select Set as StartUp Project.

  2. Press CTRL+F5 to build and run the application. Try to guess the number in as few turns as possible.

    For instructions about how to add persistence to a workflow application, see the next topic, How to: Create and Run a Long Running Workflow.

Example

The following example is the complete code listing for the Main method.

Note

Please replace Workflow1 in these examples with FlowchartNumberGuessWorkflow, SequentialNumberGuessWorkflow, or StateMachineNumberGuessWorkflow, depending on which workflow you completed in the previous How to: Create a Workflow step.

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
static void Main(string[] args)
{
    AutoResetEvent syncEvent = new AutoResetEvent(false);
    AutoResetEvent idleEvent = new AutoResetEvent(false);

    var wfparams = new Dictionary<string, object>() { { "MaxNumber", 100 } };

    WorkflowApplication wfApp =
        new WorkflowApplication(new Workflow1(), wfparams);

    wfApp.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.Aborted = delegate(WorkflowApplicationAbortedEventArgs e)
    {
        Console.WriteLine(e.Reason);
        syncEvent.Set();
    };

    wfApp.OnUnhandledException = delegate(WorkflowApplicationUnhandledExceptionEventArgs e)
    {
        Console.WriteLine(e.UnhandledException.ToString());
        return UnhandledExceptionAction.Terminate;
    };

    wfApp.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)
        {
            int Guess;
            if (!Int32.TryParse(Console.ReadLine(), out Guess))
            {
                Console.WriteLine("Please enter an integer.");
            }
            else
            {
                validEntry = true;
                wfApp.ResumeBookmark("EnterGuess", Guess);
            }
        }
    }
}
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 WorkflowApplication(new Workflow1(), inputs);

    wfApp.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.Aborted = delegate(WorkflowApplicationAbortedEventArgs e)
    {
        Console.WriteLine(e.Reason);
        syncEvent.Set();
    };

    wfApp.OnUnhandledException = delegate(WorkflowApplicationUnhandledExceptionEventArgs e)
    {
        Console.WriteLine(e.UnhandledException.ToString());
        return UnhandledExceptionAction.Terminate;
    };

    wfApp.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)
        {
            int Guess;
            if (!Int32.TryParse(Console.ReadLine(), out Guess))
            {
                Console.WriteLine("Please enter an integer.");
            }
            else
            {
                validEntry = true;
                wfApp.ResumeBookmark("EnterGuess", Guess);
            }
        }
    }
}

See Also

Tasks

How to: Create and Run a Long Running Workflow

Reference

WorkflowApplication
Bookmark

Other Resources

Windows Workflow Foundation Programming
Getting Started Tutorial
How to: Create a Workflow
Waiting for Input in a Workflow
Hosting Workflows