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

本主题适用于 Windows Workflow Foundation 4。

Windows Workflow Foundation (WF) 的一个主要功能就是运行时能够在数据库中持久保存和卸载空闲的工作流。本主题演示如何为工作流持久性创建本地数据库以及如何在工作流应用程序中启用持久性。

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

创建持久性数据库

  1. 打开 SQL Server Management Studio 并连接到本地服务器。右击本地服务器上的**“数据库”节点,然后选择“新建数据库”。将新数据库命名为 Persistence,接受所有其他值,然后选择“确定”**。

    Dd489452.note(zh-cn,VS.100).gif注意:
    在尝试创建一个新的数据库之前,确保您在本地服务器上具有“创建数据库”权限。

  2. 右击新的**“Persistence”数据库并选择“新建查询”**。打开以下文件夹:C:\Windows\Microsoft.NET\Framework\<当前版本>\sql\en。将以下文件拖动到查询窗口中并按以下顺序执行它们:

    • SqlWorkflowInstanceStoreSchema.sql

    • SqlWorkflowInstanceStoreLogic.sql

在工作流应用程序中启用持久性

  1. 在**“解决方案资源管理器”中右击“WorkflowConsoleApplication1”,然后选择“添加引用”**。

  2. 从**“.NET”选项卡中选择“System.Runtime.DurableInstancing”“System.Activities.DurableInstancing”,然后单击“确定”**。

  3. 在**“WorkflowConsoleApplication1”项目中打开“Program.cs”(对于 Visual Basic 为“Module1.vb”**)。在 Program 类(对于 Visual Basic 为 Module1)中,声明一个字符串常量以定义与您在第一个过程中创建的持久性数据库的连接。

    Const connectionString As String = "Server=.\\SQLEXPRESS;Initial Catalog=Persistence;Integrated Security=SSPI"
    
    const string connectionString = "Server=.\\SQLEXPRESS;Initial Catalog=Persistence;Integrated Security=SSPI";
    
    Dd489452.note(zh-cn,VS.100).gif注意:
    根据您的 SQL Server 版本,该连接字符串服务器的名称可能有所不同。

  4. 接下来,为**“Program.cs”“Module1.vb”**文件中的 System.Activities.DurableInstancing 添加一个 usingImports 语句。

    Imports System.Activities.DurableInstancing
    
    using System.Activities.DurableInstancing;
    
  5. 在创建 WorkflowApplication 的代码后面的 Main 方法中,创建一个 SqlWorkflowInstanceStore 并将其分配给 WorkflowApplication 中的 InstanceStore

    Dim inputs As New Dictionary(Of String, Object)
    inputs.Add("MaxNumber", 100)
    
    Dim wfApp As New WorkflowApplication(New Workflow1(), inputs)
    
    Dim store As New SqlWorkflowInstanceStore(connectionString)
    wfApp.InstanceStore = store
    
    WorkflowApplication wfApp =
        new WorkflowApplication(new Workflow1(), inputs);
    
    SqlWorkflowInstanceStore store = new SqlWorkflowInstanceStore(connectionString);
    wfApp.InstanceStore = store;
    
  6. 接下来,告知工作流在进入空闲状态时进行持久保存。为此,请将在上一主题中添加的 Idle 事件的委托替换为处理 PersistableIdle 的以下代码。

    ' Replace the Idle handler with a PersistableIdle handler.
    'wfApp.Idle = _
    '    Sub(e As WorkflowApplicationIdleEventArgs)
    '        idleEvent.Set()
    '    End Sub
    
    wfApp.PersistableIdle = _
        Function(e As WorkflowApplicationIdleEventArgs)
            idleEvent.Set()
            Return PersistableIdleAction.Persist
        End Function
    
    // Replace the Idle handler with a PersistableIdle handler.
    //wfApp.Idle = delegate(WorkflowApplicationIdleEventArgs e)
    //{
    //    idleEvent.Set();
    //};
    
    wfApp.PersistableIdle = delegate(WorkflowApplicationIdleEventArgs e)
    {
        idleEvent.Set();
        return PersistableIdleAction.Persist;
    };
    
    Dd489452.note(zh-cn,VS.100).gif注意:
    PersistableIdleAction 枚举具有三个值:NonePersistUnloadPersist 可持久保存工作流,但无法卸载工作流。Unload 可持久保存和卸载工作流。卸载实例之后,会释放 WorkflowApplication,并且下次与卸载的工作流交互时需要一个新的 WorkflowApplication 对象。在本主题中,使用了 Persist 以使工作流保留在内存中并且不释放 WorkflowApplication。有关将 WorkflowApplicationUnload 枚举值一起使用的示例,请参见持久保存工作流应用程序 示例。

  7. Main 方法的结尾处,添加以下几行代码。WorkflowApplication 会在游戏完成之后自动从内存中卸载工作流实例并从数据库中移除持久性记录。

    Console.WriteLine("Press any key to continue . . .")
    Console.ReadKey()
    
    Console.WriteLine("Press any key to continue . . .");
    Console.ReadKey();
    
    Dd489452.note(zh-cn,VS.100).gif注意:
    工作流完成之后,将移除工作流的持久性记录。在此示例中,由于没有使用 Console.ReadKey,因此,当工作流完成时,宿主应用程序会立即退出。由于持久性清理发生在后台线程中,因此,如果宿主在完成清理之前终止,则将没有机会完成其工作。防止宿主在持久性操作完成之前退出的另一个方法是使宿主出现阻塞,直到工作流完成后发生 Unloaded 事件为止。当一个工作流完成之后,在后台工作(例如从持久性中移除已完成的工作流)完成之前,它将不会被卸载。

  8. 若要测试持久性,请按 F5 键启动应用程序,并切换回 SQL Server Management Studio。展开**“Persistence”数据库节点(如果您在 Master 数据库中创建持久性表,则展开“Master“)以及“Persistence”数据库中的“表”节点。右击“InstancesTable”表,然后选择“选择前 1000 行”**。此时应显示一行以及已持久化工作流的工作流 ID。

    接下来,逐步完成该游戏以完成工作流。退出该游戏之后,回到 SQL Server Management Studio 并再次执行该查询。请注意,不返回持久性记录。

    现在,您已完成了入门教程。