《WF编程》系列之16 – 工作流与外部世界:生存周期事件

3.2 工作流与外部世界

 

对许多工作流来说,有一个重要的步骤是决定工作流与应用程序之间如何交互.我们如何得知工作流是否顺利完成?如何从运行中的工作流实例获取数据?如何获取已经完成的工作流的数据?这一节,我们来介绍一些解决这些问题的基本技术原理.

工作流的基本通信机制包括事件,方法和工作流参数.应用程序可以触发工作流实例的事件,也可以从工作流Runtime接收工作流实例的生存周期事件.首先我们来讨论一下工作流的生命周期事件.

3.2.1 工作流实例生存周期事件

WorkflowRuntime类是进入所有正在运行的工作流的大门.WorkflowRuntime公开了许多事件,我们可以利用这些事件来监听正在运行的工作流的变化.这些事件如下表所示:

名称 描述
WorklowAborted 当实例被中断时触发.WorkflowInstance类包含一个Abort方法来中断工作流.
WorklowCompleted 当实例完成时触发,包含一个WorkflowCompletedEventArgs参数来获取任何输出参数.
WorklowCreated 在使用WorklowRuntime的CreateWorkflow方法创建了工作流之后触发.
WorklowIdled 当工作流进入空闲状态时触发.当工作流在等待计时器或者外部事件发生时会进入空闲状态.
WorklowLoaded 当持久化服务将工作流实例恢复到内存中使其继续执行时触发.
WorklowPersisted 当持久化服务持久化了工作流时触发.工作流进入空闲状态时可以被持久化并从内存中卸载.
WorklowSuspended 当Runtime暂停了工作流(通常是由于工作流中的SuspendActivity活动)时触发.
WorklowResumed 当工作流执行过程从暂停中恢复时触发.
WorklowStarted 当工作流开始执行时触发.
WorklowTerminated 当工作流被终止时(通常是由于未捕捉的异常,该异常对象中包含WorkflowTerminatedEventArgs)触发.
WorklowUnloaded 当Runtime从内存中卸载工作流时触发,通常是因为工作流进入了空闲状态.

OK,实践一下,新建一个Sequential Workflow Console Application项目,名为chapter3_sequential,项目中的WorklowEvents.xoml包含一个Code活动和一个Suspend活动,工作流的设计视图如下:

Code活动只负责在控制台中输出一条消息,WorklowEvents的代码如下:

using System;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Collections;
using System.Drawing;
using System.Workflow.ComponentModel.Compiler;
using System.Workflow.ComponentModel.Serialization;
using System.Workflow.ComponentModel;
using System.Workflow.ComponentModel.Design;
using System.Workflow.Runtime;
using System.Workflow.Activities;
using System.Workflow.Activities.Rules;
namespace chapter3_sequential
{
public sealed partial class WorklowEvents: SequentialWorkflowActivity
{
public WorklowEvents()
{
InitializeComponent();
}
private void codeActivity1_ExecuteCode(object sender, EventArgs e)
{
Console.WriteLine("Executing");
}
}
}

然后将SuspendActivty的Error属性设置为intentionally suspended.

编写Program.cs的代码如下:

#region Using directives
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Workflow.Runtime;
using System.Workflow.Runtime.Hosting;
#endregion
namespace chapter3_sequential
{
class Program
{
static void Main(string[] args)
{
using(WorkflowRuntime workflowRuntime = new WorkflowRuntime())
{
AutoResetEvent waitHandle = new AutoResetEvent(false);
//工作流创建
workflowRuntime.WorkflowCreated += delegate(object sender, WorkflowEventArgs e)
{
Console.WriteLine("Workflow created");
};
//工作流开始
workflowRuntime.WorkflowStarted += delegate(object sender, WorkflowEventArgs e)
{
Console.WriteLine("Workflow started");
};
//工作流空闲
workflowRuntime.WorkflowIdled += delegate(object sender, WorkflowEventArgs e)
{
Console.WriteLine("Workflow idled");
};
//工作流暂停
workflowRuntime.WorkflowSuspended += delegate(object sender, WorkflowSuspendedEventArgs e)
{
Console.WriteLine("Workflow suspended");
//输出SuspendActivty的Error属性内容
Console.WriteLine("\tReason: " + e.Error);
//让工作流恢复执行
e.WorkflowInstance.Resume();
};
//工作流恢复
workflowRuntime.WorkflowResumed += delegate(object sender, WorkflowEventArgs e)
{
Console.WriteLine("Workflow resumed");
waitHandle.Set();
};
//工作流完成
workflowRuntime.WorkflowCompleted += delegate(object sender, WorkflowCompletedEventArgs e)
{
Console.WriteLine("Workflow completed");
waitHandle.Set();
};
//工作流终止
workflowRuntime.WorkflowTerminated += delegate(object sender, WorkflowTerminatedEventArgs e)
{
Console.WriteLine("Workflow terminated");
Console.WriteLine("\tException: " + e.Exception.Message);
waitHandle.Set();
};
WorkflowInstance instance = workflowRuntime.CreateWorkflow(typeof(chapter3_sequential.WorklowEvents));
instance.Start();
Console.Read();
waitHandle.WaitOne();
}}}}

代码中有两个事件(Terminated和Completed)需要执行WaitHandle对象的Set方法.我们在第一章中讨论过,Runtime的默认是在后台线程执行工作流.我们需要通过WaitHandle对象的WaitOne方法来阻止主线程的执行,该方法会使主线程一直等待Set方法发出的完成信号.如果我们不等待完成信号,主线程就会退出,应用程序将在工作流执行之前终止.

现在来执行一下:

如果执行过程遇到了不能继续的点,我们不希望发生异常而去终止工作流,这时,我们用SuspendActivty中断了工作流并触发了WorkflowSuspended事件,其EventHandler的WorkflowSuspendedEventArgs中也会包含Error属性的内容.

当WorkflowSuspended事件触发后,我们输出了一条消息并且直接让工作流实例去恢复操作.工作流从停止的地方继续执行到完成.

工作流实例事件不是唯一可以监视工作流执行过程的技术,工作流跟踪服务也可以接收关于工作流状态的粗粒化(exceptionally granular)信息.WF提供SqlTrackingService类来将跟踪日志信息记录到SQL Server数据库,而且我们还可以实现自定义跟踪服务并在Runtime中启用.

例程下载: chapter3_sequential.zip

7 Comments

  1. Mapleleaf

    请问一下楼主:原文:"代码中有两个事件(Terminated和Completed)需要执行WaitHandle对象的Set方法"

    我把Terminated和Completed的.Set()全都删除了 可代码还是可以运行!而且和有.Set()的效果是一样的,是不是Runtime在后台执行有什么具��的变化呢?我的环境是VS2008 sp1

  2. @Mapleleaf

    你把最后几行代码改成这样:
    instance.Start();
    waitHandle.WaitOne();
    Console.WriteLine("finish.");
    Console.Read();

    然后对比一下有WaitHandle.Set()和没有WaitHandle.Set()有什么不同。

  3. –引用————————————————–
    Windie Chai(笑煞天): @Mapleleaf

    你把最后几行代码改成这样:
    instance.Start();
    waitHandle.WaitOne();
    Console.WriteLine("finish.");
    Console.Read();

    然后对比一下有WaitHandle.Set()和没有WaitHandle.Set()有什么不同。
    ——————————————————–

    我没有测试,我想结果就会是程序主线程不等工作流的线程自己先执行完了,显示上就会是Finish会在completed的前面显示出来。不知道���不?

  4. cc

    不是的,由于没有执行waitHandle.set(),在工作流结束后,控制台将无法被唤醒(之前执行waitHandle.WaitOne()将控制台挂起缺没把他唤醒)

  5. 斯林波

    //工作流恢复
    workflowRuntime.WorkflowResumed += delegate(object sender, WorkflowEventArgs e)
    {
    Console.WriteLine(“Workflow resumed”);
    waitHandle.Set(); //此处的waitHandle.Set();
    };

    //处加上了 waitHandle.Set();
    会使主程序提前执行,导致工作流没能按计划完成!

发表评论

电子邮件地址不会被公开。 必填项已用*标注