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(删除)操作,这样我们就能从零开始编制一个工作流了。

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

如果展开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里面。现在,我们的设计器就是下面这个样子:

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

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(选择条件)对话框就会弹出来。

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

我们打算让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方法将其设为信号状态。

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

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

【翻译习作】 Windows Workflow Foundation程序开发-第一章05的更多相关文章

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

    1.2.3  Windows Workflow运行时 从Windows Workflow的角度看,可以将工作流活动当成是交给一个工作流处理器去执行的一系列指令或操作码.在Windows Workflo ...

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

    1.2.2.Visual Studio 2005扩展包 微软也为Windows Workflow开发者提供了Visual Studio 2005扩展包.扩展包将许多功能集成到Visual Studio ...

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

    1.2      Windows Workflow概览 微软的Windows Workflow Foundation(简称WF)是.NET框架3.0版的一部分..NET3.0其它主要部分是Window ...

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

    第 1 章    欢迎来到工作流的世界 …思想如蝴蝶般飞到我身边 —— Gossard / Vedder (译注:Gossard与Vedder是来自Pearl Jam乐队的2名乐手,该句出自他们的歌曲 ...

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

    近期整理硬盘,把09年的翻译习作<Windows Workflow Foundation程序开发>找出来了.现在又把译文过了一遍,做了些修改,贴出来献丑了.原书是<Programmi ...

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

    Windows Workflow Foundation程序开发-基于XAML和C#的WF实战技术与例程 ——C#程序员的WF功能与编程接口技术指导 前言 Windows Workflow Founda ...

  7. 你还记得windows workflow foundation吗

    很多年前,windows workflow foundation还叫WWF,而直译过来的名称让很多人以为它就是用来开发工作流或者干脆就是审批流的. 博主当年还是个懵懂的少年,却也知道微软不会大力推一个 ...

  8. Workflow-Microsoft:Windows Workflow Foundation

    ylbtech-Workflow-Microsoft:Windows Workflow Foundation 1. Windows Workflow Foundation返回顶部 1.1. Windo ...

  9. 微信小程序开发-第一弹

    前言:       本篇文章为大家详细介绍微信小程序开发第一篇,后续步骤会逐步更新,欢迎大家关注. 第一步  注册        1.1 打开网址 https://mp.weixin.qq.com/  ...

随机推荐

  1. SPOJ #752. Power it!

    By property of mod operations , we can simply use Divide and Conquer + Recursion to solve it. Refere ...

  2. 样本方差:为嘛分母是n-1

    在样本方差计算式中,我们使用Xbar代替随机变量均值μ. 容易证明(参考随便一本会讲述样本方差的教材),只要Xbar不等于μ,sigma(Xi-Xbar)2必定小于sigma(Xi-μ)2. 然而,要 ...

  3. python主要用来做什么

    python这门编程语言在国外极受欢迎,但在国内使用还不是极普遍. 由于python编程效率极高,现在国内的使用者也开始变得越来越多. python主要用来做什么?这个语言到底有哪些作用呢? 下面主是 ...

  4. Java事务处理全解析(三)——丑陋的案例

    在本系列的上一篇文章中,我们看到了一个典型的事务处理失败的案例,其主要原因在于,service层和各个DAO所使用的Connection是不一样的,而JDBC中事务处理的作用对象正是Connectio ...

  5. C#学习笔记四: C#3.0自动属性&匿名属性及扩展方法

    前言 这一章算是看这本书最大的收获了, Lambda表达式让人用着屡试不爽, C#3.0可谓颠覆了我们的代码编写风格. 因为Lambda所需篇幅挺大, 所以先总结C#3.0智能编译器给我们带来的诸多好 ...

  6. jetty-run运行报错的原因

  7. C++14使用std::integer_sequence展开tuple作为函数的参数

    元组是一种长度固定的允许有不同类型元素的集合,根据元素的个数不同又分别称作一元组.二元组.三元组等.C++11中标准库增加了一个叫std::tuple的类模板,用于表示元组. 下面的代码演示了使用C+ ...

  8. ruby1.8到2.1语法改变

    1定义hash的语法改变old_way = {:foo => "bar", :one => 1}new_way = {foo: "bar", one ...

  9. 新找到的一款字体 fantasque-sans-mono

    http://www.ipreferjim.com/2015/03/your-ides-font-matters-fantasque-sans-mono/

  10. 第10章 Posix 信号量

    10.1 概述 10.1.1 信号量类型 Posix有名信号量:使用Posix IPC名字,可用于进程或线程间同步: Posix基于内存的信号量:也叫做无名信号量,存放在共享内存中,可用于进程或线程间 ...