学习完本章,你将掌握:
1.workflow 活动是怎样形成的
2.顺序工作流和状态机工作流之间的区别
3.创建一个顺序工作流
4.创建一个状态机工作流
活动是WF 中workflow 处理的基本单位,假如你再把一个业务处理过程(或workflow 任务)进行分解,你会发现它由更小、更细的 任务组成。假如需设计这样一个大的任务,它需把信息送到一系列的数据处理系统进行处理,那么子任务或许就包括这样一些事情:从数据库读取数据,使用这些数 据生成一个文件,通过使用FTP 或XML Web service 把文件传到一个远程服务器上,标记信息已经被处理(如通过写入数据库并进入审计步骤),等等。这些子任务都聚焦到一个特定的任务上:读数据 库、上传文件、进行审计。换句话说,它们是活动。
当你创建workflow 时,你会把这些单独的活动捆在一起,并让活动从一个转到另一 个。
一些活动可作为其它活动的容器。一些活动执行一个单一任务,这我们已谈过。基于容器的活动用来容纳其它活动,在前一章中我们谈及的root 活动就是这 种活动。root 活动既可是一个顺序活动也可是一个状态机活动,本章中我们将对这些活动的类型进行说明。
活动怎样知道在本步骤完成后下一 步将做什么呢?本章将主要把焦点放在这上面上。或许活动会以你创建一个root 活动时指定的顺序执行,或者可能是仅在一个特定的事件发生后才去执行一个指 定的活动。为了让我们更好地理解活动,我们首先要去看看WF Activity 对象,然后看看活动是怎样链接在一起的。
活动介绍:基本的工作单位
WF 为你提供了一个Activity 对象。Activity 实现了一个看起来很简单的基类。它不会
做许多智能任务,但它可进行workflow 的相互交互(这可不简单)。活动对象由“Activity”
派生,提供 出了强悍的功能。你可自如地创建你自己的活动,这个话题将在第13 章(自定
义活动)进行介绍。事实上,本书的第二部分都是在介绍活动(第7 章至第13 章)。表4-1
列出了许多我们通常感兴趣的Activity 的属性,表4-2 列出了你会经常用到的方法。在第
13 章,你还会看到更多的和自定义活动相关的 方法和属性。
表4-1 活动(Activity)的属性
属性 功能
Description
获取或设置用户定义的关于活动的描述。
Enable
获取或设置一个指明实例能否被执行和验证的值。
ExecutionResult
获取实例最后运行的结果(ActivityExecutionResult)。(有Canceled、Compensated、Faulted、None 和Succeeded)。
ExecutionStatus
得到workflow 的状态,其为ActivityExecutionStatus 的枚举值(Canceling、Closed、Compensating、Executing、Faulting 和
Initialized)之一。
Name
获取或设置活动实例的名称。
Parent
获取包含本活动的父活动。
WorkflowInstanceId
获取和该活动相关的workflow 实例的标识符。
表4-2 活动(Activity)的方法
属性 功能
Cancel
取消活动的执行。
Clone
返回活动的一个深拷贝。
Execute
以同步方式运行活动。
GetActivityByName
假如在一个组合活动上执行,本方法将返回组合活动中所包含的指定名称的活动。
Load
从一个流中加载一个活动的实例。
RaiseEvent
触发一个和指定的依赖属性相关的事件。
RaiseGenericEvent<T>
触发和所引用的依赖属性相关的事件。RaiseEvent 和RaiseGenericEvent 的作用是一样的——第一个事件RaiseEvent 直接指出DependencyPropenty,而RaiseGenericEvent 则是一个泛型版本。
Save
把活动保存到流中。
活动的方法通常都具有虚拟和受保护的属性。目的是你可去覆盖它们,使其提供一个符合你自己的活动所需要的实现。目前为止,最关键的方法是Execute。当workflow 运行时调用这个方法时,你的活动便开始执行了。
活 动可被分为两个大类:组合活动和基本活动。组合活动包含其它活动。一个极好的例子是我们目前为止贯穿书中的Sequential 活动(译者注:它是基于顺 序工作流中所有活动的载体,在创建一个顺序工作流时Visual Studio 就已为我们创建好了,可在视图设计器中看到)。目前为止所有的程序实例执行workflow 实例的方式都是Sequential 活动,它包含 其它活动,如它自身、Delay 活动和Code 活动。
基本活动,就像我刚谈到的Delay 活动和Code 活动,它们是一个基于单一任务的活动,我在本章早些时候谈过它。最终,你需要基本活动去实际承载特定的任务。组合活动或许可指挥任务和数据的流动,但基本活动能做更多。
ActivityExecutionContex对象
许多Activity 对象的方 法需要一个ActivityExecutionContext 对象来进行输入。在workflow 运行时把你要执行的workflow 实例入队的时候 ActivityExecutionContext 对象被创建,因此,它不是你直接要创建的对象。workflow 运行时为你创建它。
ActivityExecutionContext 对象的作用是提供活动以方法和服务,以便和workflow 实例挂钩。这些如初始化,定时器和产生执行流。它本质上是一个helper 对象。在13 章将更详细的对活动上下文(环境)进行讨论。
备 注:假如你熟悉ASP.NET 编程的话,这个context 对象本质上和System.Web.HttpContext 对象的作用是一样的。其它相似的还 有System.Threading.Thread.CurrentContext。所有这些Context 对象的目标都是一样的:提供一个存储位置并容 易地恢复一个当前执行实例的信息。这种情况下,它是一个执行当中的活动的一个实例。
依赖属性(Dependency Properties)
在表4-2 中,你将看到一些依赖属性(DependencyProperty)。什么是依赖属性呢?
通常,假如你为类创建了一个属性的话,你也会在类中创建一个字段来存储该属性的值。
普遍的代码如下:
class MyClass { protected Int32 _x=0; public Int32 X { get { return _x;} set { _x = value; } } }
字段_x 更正式的叫法是backing store。在这个例子中,你的类为X 属性提供了backing store。
然而,WF 和WPF 通常都非常需要去访问你类中的属性。WPF 需要指明容器中控件的空间和大小以便能最佳地被render。WF 需要依赖属性来方便地进行活动绑定。WF 中ActivityBind类可为你方便地进行活动绑定。
活动验证
活动通常都具有验证能力,你可回忆第一章。
在第一章的例子中 有这样一种情况,如在IfElse 活动中未指定应该选择哪一个分支进行执行的条件时,Visual Studio 会提醒我们。其它活动实现了不同的验证算法。假如我们编译带有验证错误的代码,我们的编译都会失败。我们必须纠正这些验证条件不充分的代码,才能编译和执行我们的workflow 代码。
workflow类型
你已创建过workflow 应用程序,因此你可能注意到可以创建不同类型的workflow 应用。
workflow 应用程序的类型很大程度上依赖于你选择的root 活动。
尽管你注意到在新项目对话框中仅仅只有两种workflow 类型的应用程序可供选择,但实际运用中存在三种主要的类型。迄今为止本书中你已经创建过顺序工作流,因此它们并不神秘。
当你创建workflow 时,你的活动以你规定的顺序执行。
另一种从新项目对话框中看到的workflow 类型是状态机工作流。我将在本章讨论它的更多细节。
第三种workflow 类型基于顺序工作流,但它是规则驱动的。它不是仅仅执行你指定的任务,而是由Policy 活动和规则条件组成的基于规则的orkflow,来执行基于你指定的业务规则workflow 任务。
我们将在12 章更多地学习这种workflow 类型:“Policy 活动”。因为这种类型的workflow以顺序活动作为root,因此在新项目对话框中没有这种类型的workflow 应用程序的模板可供选择。你应以顺序工作流作为起始,然后增加基于规则的活动。
选择一种workflow类型
在什么情况下一种类型的workflow 比另一种类型的workflow 更好?你如何选择合适的
workflow 类型呢?
表4-3 可为你提供一些基本的参考。
表4-3 选择基本的workflow 类型的判定表
顺序工作流的理想应用是去执行业务处理。假如你需要从源中读数据,处理这些数据,发送通知,往你的一个数据池中写入结果的话,顺序工作流或许将符 合你的需求。这并不意味着顺序工作流不适合处理依赖于用户交互的特定任务,如赞同或不同意之类的审批任务。
其实这样一些的用户交互不应成为 workflow 自身的关注焦点。
假 如你需要大量的用户交互,当你的workflow 发送通知给用户或其它系统(有各种原因:通知、需要批复、选择一个选项等等)以使用户或其它系统进行响应 (它们的响应来自事件)时,状态机工作流可能是更好的选择。这些事件触发了workflow 从一种处理状态转化到另一种处理状态。我将在本章后面及14 章 (“基于状态的工作流”)更多地讨论这些。
最后一种workflow 类型(我们将在12 章看到)是基于规则的workflow。这些workflow基于业务规则判定是否进行转化,并判定转化后的目标是什么。这些workflow 通常都预置了更加复杂的剧情。
你或许会认为所有的workflow 都能以基于规则的工作流类型来创建,但我们通常并不总是使用这种方式进行创建。因为其它的workflow 类型,如顺序工作流和状态机工作流,它们能更容易地创建和测试。
要用最合适的workflow 类型来构建你的系统。通常,在许多真实案例中你会发现你自己使用了所有三种workflow 类型的组合。
顺序活动
让我们进一步深入顺序复合活动吧。尽管迄今为止我们使用这些活动贯穿本书,但 我在之前有意地拖延谈论关于它的更多内容。现在我们去理解了workflow 运行时和workflow 实例是怎样工作的,并且知道workflow 实例是 我们正运行中的workflow 活动的版本,我们能更好的了解发生了什么。
执行顺序活动意味着这些活动以一个指定的顺序执行。首先要做的 事最先执行,最后才做的事最后执行。一个顺序活动就像在根据目录执行。你需要记下首先要做的任务,接下来要做的任务和最后要做的任务。假如这些任务以顺序 活动的方式存储,WF 将以你指定的顺序精准地执行每个任务。
备注:本书中我们不会看到以动态的方式添加活动,但你应知道这是可以做到的。在 Visual Studio 中,workflow 的视图设计器可帮你展示你的workflow。当你创建一个顺序工作流应用程序并在设计器中打开root 活动时,你可把 任务放到屏幕的最上方以便首先被执行。那些朝向底部的任务将晚些执行。从可视化界面可看出,活动运行的顺序是从上到下。当然顺序活动还可以是一个复合活 动。
创建顺序工作流
在本书中迄今为止我们已创建过一些顺序工作流应用程序,因此这里我不再创建它们。
但我还是把完整的步骤重复一下。
建立一个顺序工作流应用程序
1.打开Microsoft Vistual Studio 2008。
2.在文件菜单上,选择新建项目。然后将呈现新项目对话框。
3.在项目类型面板中,展开Vistual C#树形节点,呈现出基于workflow 项目的模板。
4.在模板面板中,点击顺序工作流控制台应用程序或顺序工作流库。前者创建一个可执
行的应用程序并以控制台的方式执行,而后者创建一个动态链接库并在其它应用程序中使用。
5.输入你的项目或应用程序的名称。
6.输入或选择你想保存你的项目的所在路径。
7.点击确定,Visual Studio 2008 将为你建立一个基本项目,其中包含workflow 视图
设计器用户界面。
然后,你就可方便地从工具箱中拖拽你需要的活动,调整它们的属性以符合你的需求。
假如你需要增加更多workflow 库的项目,你可参考我前一章中的描述,或者简单地直接在你的应用程序中增加一个新的workflow 类。接下来我们还会看到大量的例子。
状态活动
迄今为止在本书中我们还未看到过状态机工作流。14 章完全把焦点放到基于状态的工作流的工作上,但我在这里将介绍一些概念,我们也会快速地创建一个基于状态的工作流。
看看这样一个术语:有限状态机。我们把这个术语分成三个词:有限、状态和机器。有限,意思是我们将进行转化的状态的数目是有限的。状态是我们的应用程序在事件发生时进行转化的逻辑条件。机器则意味自动化。我将用一个例子来阐明。
在 工程学校,或许会要求你使用有限状态机来设计一些数字系统。例如自动售货机和洗衣机。看看自动售货机,思考一下机器工作必须具有的步骤,以便它能为你提供 你需要的商品(如汽水、糖果、点心等等)。当你投入硬币时,它会合计你投入的硬币金额,直到你投入的硬币金额能购买商品时为止。当你选择一个商品时,它会 检查存货清单。假如有货,它就把你选择的东西分发给你。
我们可以使用有限状态机来构建自动售货机。在有限自动机的图示中,我们使用圆来表示状态,箭头来表示状态之间的转换,转换由事件触发。图中有一个逻辑上的起点和一个或多个逻辑上的终点。假如我们停在其它地方,我们的应用程序就被称作未 指定状态或者无效状态。我们的工作就是防止无效状态,如我们不能免费地获取商品,我们也不应该接收超过商品价格的多余的钱。假如自动售货机接受了钱但又未 提供商品的话,用户毫无疑问会暴怒。
假象一下简化的自动售货机,让我们画出状态和导致状态转换的事件吧。正如我提到的,状态用圆来表示。使你的机器从一个状态变为另一个状态的事件用箭头表示。它们都可命名以便我们知道这些是什么状态和相关的转换。我们毫无疑问需要一个开始状态,如下图:
图4-2 有限状态机起始状态符号
这 个状态表示机器所处的这样一个位置:等待有人来投入一个硬币。因此看看当有人来投入一个硬币,但它还不够买一个商品的情况,我们通过创建一个新状态来进行 模拟,这个状态叫WaitCoins(等待硬币)状态,通过CoinInserted(投入硬币)事件转换到该状态,
如图4-3:
图4-3 转换到WaitCoins 状态
在 用户投入足够金额的钱以能购买其中的商品之前,机器一直处在WaitCoins 状态,并接受CoinInserted 事件,否则会触发 SufficientCoins(金额足够)事件使我们的机器转到WaitSelection(等待选择)状态。在这里我们的自动售货机会耐心地等待用户 选择一个商品。(在实际生活中,用户也能在任何时候要回投入的硬币,为了简单起见,本例还是不考虑它吧。)
当用户选择商品后,商品会被分发给用户,我们的(状态)转换也就结束了。完成状态,或者称作结束状态,由二个圆圈来指明,参见图4-4。
图4-4
尽 管这个自动售货机在现实世界中或许太过于简单,但此处只是期望为你提供一个的简要描述,使你明白状态机是如何工作的。当我们设计状态机时,我们指明其离散 的状态,或者逻辑位置来等待事件发生,然后我们指明转换机器状态的事件。有些事件可让机器返回到同一状态,如开始状态。其它事件则会在一个新的事件被处理 后使机器转换到一个新的状态。
没有事件被触发就没有状态的转换,理想情况下应没有无法预料的事件或异常。这种模型和我们用过的顺序工作流 模型有很大的不同。在顺序工作流里,活动以指定的顺序依次执行。一旦在该顺序链上的一个活动执行完它的任务,在该链上的下一个活动就开始执行它的工作。在 workflow 处理中或许有事件参与其中,但它们在workflow 任务的处理(如定时器事件)上相对简单。
但状态机会花费大量时间在 等待上。它们等待事件,依赖事件来使它们的状态进行转换。
状态自身不会激发事件(尽管它们可能会调用外部代码)。它们就是事件处理,因此它们会耐心地等待 它们需要的事件来进行状态的转换。依靠事件,它完全可能从一个状态切换到任何一个离散的不同的状态。假如我们的自动售货机处在WaitCoins 状态,当 接受一个CoinInserted 事件、RefundRequested 事件或ImminentPowerdown 事件时会分别做不同的事情。但我并未在 图4-4 中这个经过简化的模型里画出这些事件,但我相信你能看懂不同的事件是怎样驱动你的有限状态机转换到不同状态的。
在WF 里,基于状态的workflow 内的个别状态由State 活动创建。State 活动是一个复合(组合)活动,但它对容纳的子活动有限制。你将在14 章学习到基于状态的workflow 的更多东西。
备 注:正如顺序工作流使用一个特别的Sequence 活动来容纳整个工作流一样,基于状态的工作流也有一个特别的root 活动做这事,这就是 StateMachineWorkflow 活动,它是一个特别的State 活动。特别之处是它是必须的,这样当初始化执行时root 活动就能接受初始化参 数。
创建一个状态机工作流应用程序
怎样创建一个基于状态的workflow 呢?创建一个基 于状态的工作流和创建一个顺序工作流一样容易。我们现在就来看看怎样创建一个状态机工作流。然而我们现在不会添加任何代码——虽然本书后面有很多时候需我 们这样去做,但我们现在只要需要了解怎样创建一个状态机工作流就行了。
创建一个状态机工作流应用
1.启动Microsoft Visual Studio 2008。
2.在文件菜单上,选择新建一个项目,这将打开新建项目对话框。
3.展开项目类型面板中的Visual C#节点,这将显示所有使用C#语言的项目类型。
4.在Visual C#节点下点击Workflow 节点,这将显示所有基于工作流的项目模板。
5.在模板面板内,点击状态机工作流控制台应用程序或状态机工作流库。如下图所示:
6.输入程序或项目的名称。
7.输入或选择项目文件要保存的位置。
8.点击确定。Visual Studio 2008 将为你创建一个包含workflow 视图设计器用户界面
的项目,如下图:
我们需要去触发引发工作流改变状态的事件,因此,我们需理解workflow 实例是怎样和它们的宿主应用程序进行通信的。我们将在第八章(“调用外部方法”)看到宿主和workflow之间的通信,在第十章(“事件活动”)中我们将学习状态机工作流的事件驱动。
---------------------
作者:hackpig
来源:www.skcircle.com
版权声明:本文为博主原创文章,转载请附上博文链接!

