【翻译习作】 Windows Workflow Foundation程序开发-第一章05

时间:2022-03-31 16:04:43

1.3      开发我们的第一个工作流

也许你曾经在这样的产品经理手下搞过开发:他总是在你身边转悠,并不时的问一句“你还没做完吗?”。在这一部分,我们将用一个简单的Windows Workflow程序把这个招人烦的产品经理替换掉。这个例程无法向你展示WF平台的全部功能,但它可以让你领略到如何用WF创建并运行工作流。

在开始之前,我们需要下载并安装.NET 3.0框架。安装程序可以在 http://netfx3.com 找到。Visual Studio 2005的所有版本都支持在.NET 3.0框架上的开发。我们还需要下载并安装Visual Studio 2005 Extensions for Windows Workflow Foundation。这个扩展包也可以在 http://netfx3.com 找到。但是这个扩展包不支持Visual Studio 2005 的Express版本。

首先,用Visual Studio新建一个Workflow工程(File | New Project)。我们选择使用C#开发,选择Sequential Workflow Console Application(顺序工作流控制台应用程序)模板(参见下面的截屏图)。模板为我们生成的工程包含有:对所有必要的WF程序集的引用,一个空工作流和一个用来驱动工作流的Program.cs文件。右键单击这个工作流,选择Delete(删除)操作,这样我们就能从零开始编制一个工作流了。

【翻译习作】 Windows Workflow Foundation程序开发-第一章05

我们现在可以在Solution Explorer(解决方案管理器)窗口中右键单击工程文件,选择Add New Item(添加新项目)。在可添加项目列表中,我们选择Sequential Workflow(with code separation)(顺序工作流-代码分离),然后把这个新项目命名为workflow1.xoml(请见下面的截屏图)。这个XOML文件中就是用XAML标记码定义的我们的工作流。

【翻译习作】 Windows Workflow Foundation程序开发-第一章05

如果展开Workflow1.xoml节点,我们就会看到包含一个分部类的代码旁置文件(Workflow1.xoml.cs)。前面说过,这个分部类将与XAML标记码定义的类共同生成一个完整类型。在下面的代码中,我们对Workflow1.xoml.cs中的类做了修改,添加了一个IsFixed属性及其支持字段。

public partial class Workflow1 : SequentialWorkflowActivity
{
private bool _isFixed; public bool IsFixed
{
get { return _isFixed; } set { _isFixed = value; }
}
}

如果双击.xoml文件,设计器窗口就会打开。此时如果Toolbox窗口还没有打开,我们可以用快捷键Ctrl+Alt+X打开它。我们可以从Toolbox中拖出一个While活动,并放置到工作流的起始点和终止点之间。While活动会重复执行其内部的子任务,直到某个条件得到满足为止。再拖出一个Code活动,把它放到While里面。现在,我们的设计器就是下面这个样子:

【翻译习作】 Windows Workflow Foundation程序开发-第一章05

你看到了吗?每个活动都带着一个红叹号点。这就是说,两个活动的有效性验证都没通过。我们可以把鼠标停在叹号点上,点开智能标记后就能看到验证错误。如果现在就执行编译操作,验证错误就会作为编译错误出现在错误提示窗口中。让我们动手来修复这些错误。

Code活动要求我们为其ExecuteCode事件分配一个事件处理函数。我们可以在Code活动的Properties窗口中(用F4快捷键打开)完成这项分配操作。双击ExecuteCode属性旁边的空白处,相应的代码旁置文件就会打开,里面也已经有了一个自动生成的事件处理函数框架。我们把下面这段代码放到框架中。这段代码向用户询问软件缺陷是否已修复,然后等待用户按下一个键。如果用户按了“y”键,程序会将_isFixed字段设置为true。

private void codeActivity1_ExecuteCode(object sender, EventArgs e)
{
Console.WriteLine("Is the bug fixed?"); Char answer = Console.ReadKey().KeyChar; answer = Char.ToLower(answer); if (answer == 'y')
{
_isFixed = true;
}
else
{
Console.WriteLine();
Console.WriteLine("Get back to work!");
Console.WriteLine();
} }

Code活动的验证已经通过了,让我们来对付While活动。While活动需要一个有效的Condition(条件)属性。基本活动库中有好几个活动在执行时都需要“条件”,这其中就包括IfElse、ConditionedActivityGroup以及Replicator活动。第9章将会深入讨论条件与规则。

设置Condition属性的方法很简单:在Properties窗口中打开Condition属性旁边的下拉列表框,在CodeConditionRuleConditionReference中二选一。这两个供选项代表了两个不同的条件表述技术,前者用代码表述(一个返回布尔值的方法),后者用规则。这里选择RuleConditionReference一项。规则条件是一个命名表达式,它的评估结果是true或false,它能够存储在独立的.rules外部文件中,这样易于维护。现在,Condition属性旁边出现了一个加号,点击这个加号可以展开属性编辑器。

Condition属性被展开后,Properties窗口允许我们对ConditionName(条件名称)和Expression(表达式)进行设置。点击Condition旁边的省略号(…)按钮,Select Condition(选择条件)对话框就会弹出来。

【翻译习作】 Windows Workflow Foundation程序开发-第一章05

点击New Condition…(新条件…)按钮会弹出下面的Rule Condition Editor(规则条件编辑器)。

【翻译习作】 Windows Workflow Foundation程序开发-第一章05

我们打算让While活动循环执行直到缺陷被修复,因此我们输入的规则是 !this.IsFixed(编辑器自带的IntelliSense功能可以让我们偷点懒),然后点OK(确定)按钮。当返回到Select Condition对话框,可以看到编辑器已经把我们的条件命名为Condition1。请选择Condition1并点击OK。此时已经完成了对While活动ConditionNameExpression的设置,也通过了有效性验证。

现在打开Program.cs文件,这里的Main方法是控制台程序的入口点。我们需要承载WF运行时,并让它来执行我们的工作流。工作流工程模板中已经提供了所有我们需要的模板代码。请看下面的代码:

class Program
{
static void Main(string[] args)
{
WorkflowRuntime workflowRuntime = new WorkflowRuntime(); workflowRuntime.WorkflowCompleted += new EventHandler<WorkflowCompletedEventArgs> (workflowRuntime_WorkflowCompleted); workflowRuntime.WorkflowTerminated += new EventHandler<WorkflowTerminatedEventArgs> (workflowRuntime_WorkflowTerminated); WorkflowInstance instance; instance = workflowRuntime.CreateWorkflow(typeof(Workflow1)); instance.Start(); waitHandle.WaitOne();
} static void workflowRuntime_WorkflowTerminated(object sender, WorkflowTerminatedEventArgs e)
{
Console.WriteLine(e.Exception.Message); waitHandle.Set();
} static void workflowRuntime_WorkflowCompleted(object sender, WorkflowCompletedEventArgs e)
{
waitHandle.Set();
} static AutoResetEvent waitHandle = new AutoResetEvent(false);
}

第一步是生成一个WorkflowRuntime实例。代码中已经为运行时指定了两个事件处理函数,因此如果工作流终止(因为异常)或结束了,我们都能够得到相应的通知。随后调用CreateWorkflow方法生成了一个缺陷修复工作流的实例,调用参数就是我们的工作流类型。因为工作流引擎是以异步方式执行工作流,我们就必须用一个AutoResetEvent对象将主线程阻塞,并等待工作流结束(不然的话,这个控制台程序可能会在工作流开始执行前就退出了)。AutoResetEvent对象会阻塞一个线程,直到该对象进入信号状态,而我们恰好是在前面提到的两个事件处理函数中调用AutoResetEvent对象的Set方法将其设为信号状态。

现在我们可以生成这个工作流解决方案,然后在命令行中运行它的可执行文件。

【翻译习作】 Windows Workflow Foundation程序开发-第一章05

1.4      总结

软件开发者们从一开始就不断地使用工作流对业务流程进行建模与实现。在这期间,我们已经知道了工作流可能会长时间地运行,并经常需要得到用户的输入信息。通过创建一个健壮的工作流来应对这些挑战是一项令人望而生畏的任务。一种理想的工作流创建范例是将工作流的定义与工作流的执行引擎分离开。

一旦将工作流的定义与执行引擎分离,我们就可以通过构建工作流组件的方式编制出域特定语言。如果一个业务人员能够理解域特定语言,那么在忽略掉异常处理和状态追踪这些细节的情况下,他同样能够理解一个工作流。

Windows Workflow为微软平台带来了一个工作流执行引擎和一系列工作流开发工具。WF引擎的执行指令就是活动,我们可以利用图形化的设计器、XAML、代码或者它们三者的组合,对活动进行一番编排。WF还提供了一些工作流引擎所需的服务,这包括持久化服务、线程服务以及事务服务。因此我们可以说:用WF搞工作流开发,前途一片光明。

章节链接:

【翻译习作】 Windows Workflow Foundation程序开发

【翻译习作】 Windows Workflow Foundation程序开发-前言

【翻译习作】 Windows Workflow Foundation程序开发-第一章01

【翻译习作】 Windows Workflow Foundation程序开发-第一章02

【翻译习作】 Windows Workflow Foundation程序开发-第一章03

【翻译习作】 Windows Workflow Foundation程序开发-第一章04