如何:运行工作流

本主题适用于 Windows Workflow Foundation 4。

本主题是 Windows Workflow Foundation 入门教程的延续,讨论如何运行在前面的如何:创建工作流主题中定义的工作流。

Dd489463.note(zh-cn,VS.100).gif注意:
入门教程中的每个主题都依赖于前面的主题。若要完成本主题,必须先完成如何:创建活动如何:创建工作流

打开工作流宿主项目

  1. 使用 Visual Studio 2010 打开之前如何:创建工作流主题中的解决方案。

  2. 在**“解决方案资源管理器”中双击“Program.cs”“Module1.vb”**,以显示其代码。

    Dd489463.Tip(zh-cn,VS.100).gif提示:
    如果未显示“解决方案资源管理器”窗口,请从“视图”菜单选择“解决方案资源管理器

    由于此项目是使用**“工作流控制台应用程序”模板创建的,因此“Program.cs”“Module1.vb”**包含以下基本工作流承载代码。

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

    此生成的承载代码使用 WorkflowInvokerWorkflowInvoker 提供调用工作流的简单方法,就像方法调用一样,并且只可用于不使用持久性的工作流。WorkflowApplication 为执行工作流提供更丰富的模型,包括生命周期事件通知、执行控制、书签恢复和持久性。此示例使用书签并且将 WorkflowApplication 用于承载工作流。在**“Program.cs”“Module1.vb”顶部的现有“using”“Imports”语句下面,添加以下 using“Imports”**语句。

    Imports System.Threading
    
    using System.Threading;
    

    用以下基本 WorkflowApplication 承载代码替换使用 WorkflowInvoker 的代码行。此示例承载代码演示承载和调用工作流的基本步骤,但尚不包含用于成功运行本主题中的工作流的功能。在以下步骤中,将修改此基本代码并添加其他功能,直到完成应用程序。

    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();
    

    此代码将创建一个 WorkflowApplication,订阅三个工作流生命周期事件,通过调用 Run 来启动工作流,然后等待工作流完成。工作流完成时,将设置 AutoResetEvent,并且宿主应用程序也完成。

设置工作流的输入参数

  1. 在**“Program.cs”“Module1.vb”**顶部的现有 usingImports 语句下面,添加以下语句。

    Imports System.Collections.Generic
    
    using System.Collections.Generic;
    
  2. 将创建新 WorkflowApplication 的代码行替换为以下代码,该代码创建一个参数字典并在创建后将其传递给工作流。

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

    此字典包含一个键为 MaxNumber 的元素。输入字典中的键对应于工作流的根活动上的输入参数。工作流使用 MaxNumber 来确定随机生成数的上限。

检索工作流的输出参数

  1. 修改 Completed 处理程序以检索并显示工作流使用的轮数。

    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();
    };
    

继续执行书签

  1. 将以下代码添加到 Main 方法顶部,紧接在现有 AutoResetEvent 声明之后。

    Dim idleEvent As New AutoResetEvent(False)
    
    AutoResetEvent idleEvent = new AutoResetEvent(false);
    
  2. 将以下 Idle 处理程序添加到 Main 中,紧接在现有的三个工作流生命周期处理程序的下面。

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

    每次工作流变为空闲状态等待下一个猜测时,都会调用此处理程序并设置 idleAction AutoResetEvent。下面步骤中的代码使用 idleEventsyncEvent 来确定工作流是在等待下一个猜测还是已完成。

    Dd489463.note(zh-cn,VS.100).gif注意:
    在本示例中,宿主应用程序在 CompletedIdle 处理程序中使用自动重置事件将宿主应用程序与工作流的进度同步。在继续执行书签之前,不需要阻止并等待工作流变为空闲状态,但在此示例中需要同步事件,以使宿主知道工作流是否已完成,或是否在等待使用 Bookmark 的更多用户输入。有关更多信息,请参见书签.

  3. 移除对 WaitOne 的调用,并替换为收集用户输入并恢复 Bookmark 的代码。

    移除下面的代码行。

    syncEvent.WaitOne()
    
    syncEvent.WaitOne();
    

    使用下面的示例替换它。

    ' 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);
            }
        }
    }
    

生成并运行应用程序

  1. 在**“解决方案资源管理器”中,右击“WorkflowConsoleApplication1”项目,然后选择“设为启动项目”**。

  2. 按 Ctrl+F5 生成并运行应用程序。尝试以尽可能少的次数猜出该数。

    有关如何向工作流应用程序添加持久性的说明,请参见下一主题如何:创建和运行长时间运行的工作流

示例

下面的示例是 Main 方法的完整代码清单。

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 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);
            }
        }
    }
}

另请参见

任务

如何:创建工作流
如何:创建和运行长时间运行的工作流

参考

WorkflowApplication
Bookmark

其他资源

Windows Workflow Foundation 编程
入门教程
在工作流中等待输入
承载工作流