作为即将推出的 Microsoft .NET Framework 3.0 的重要组成部分,Windows Workflow Foundation 提供了编程模型和运行时引擎,以便基于安装了 .NET Framework 2.0 或更高版本的 Window 平台来构建支持工作流的应用程序,其最低运行要求为 Windows xp Service Pack 2 (SP2) 或 Windows Server 2003。
从软件的角度看,需要人为操作的多数是异步事件处理、状态保持以及共享服务器可用性。Windows Workflow Foundation 实际上支持任何涉及人为操作的情况。
每一个工作流都是一个声明程序,其中,每条程序语句都用称为活动的组件表示。关于 Windows Workflow Foundation 的最大误区之一在于将所有要素活动都看成是顺序相连或按状态机转换相连。实际上,Windows Workflow Foundation 对执行模型进行了活动自动控制方面的虚拟化。这使您能编写可以捕捉各种控制流模式的复合活动,范围包括多种连接和合并、状态机、图形、序列、交叉存取和非本地退出等。总之,它将使您能够通过“高保真”的复合活动对存在于现实世界中的控制流模式进行建模。然而,Windows Workflow Foundation 提供了针对以下两种模式的内置活动:顺序工作流和状态机工作流。
正如我所谈到的,工作流的构造块就是活动。构造这样一个工作流意味着将活动进行组合以创建所需的模型来解决碰到的问题。虽然 Windows Workflow Foundation 提供了很多内置的活动,但依然可以通过自定义活动对其进行完全扩展。了解“开箱即用”活动的目标和功能对于充分理解该平台的真实潜能十分要害。本期专栏将带您浏览安装 Windows Workflow Foundation Runtime 和 Visual Studio 2005 Designer 时涉及的标准工作流活动。
“开箱即用”活动
Windows Workflow Foundation 是 .NET Framework 3.0 (原先称为 WinFX?)的组成部分。虽然它只是一个测试版本,但我发现最新的 Community Technology PReview(社区技术预览,CTP)版非常稳定,许多公司正广泛使用该版本开发应用程序。因此,已经出现大量工具和自定义活动,一个基于新闻组和论坛(如 wf.netfx3.com)的有效的技术支持社区正日益发展壮大。假如您对工作流应用程序感爱好,那么越早熟悉它越好。
若要查找最新的下载,请访问 Windows Workflow Foundation。安装完毕后,启动 Visual Studio 2005,打开一个 Visual Basic? 或 C# 工作流项目,查看工具箱中的内容。根据您所选择的项目类型,工具箱可能如图 1 中所示的一种。
控制流活动治理图形活动执行的顺序。列表列出了实现循环的条件块以及构造。执行活动包括多种构造,这些构造可终止或挂起工作流、引发异常、执行内部或外部代码,或者生成另一个工作流。多数工作流需要与主机环境同步 — 通常是 Windows Forms 应用程序或 asp.net 应用程序。事件组中的活动能使工作流停止以等待外部事件、处理接收的事件,或只是在执行下一步之前进行等待。最后,Web 服务和状态组将目标锁定在工作流的两种非凡功能 — 将内部引擎为公开为 Web 服务或公开为状态机。让我们检查一下框架中的主要活动,然后分组进行。通过条件控制工作流
假如在工作流中指定了条件,运行时引擎将对条件进行计算,然后根据计算结果进行操作。两种基于条件的核心活动是 IfElse 和 Policy。IfElse 活动的执行方式如同高级编程语言中的一条典型的 If 语句。它可以包含任意多基于条件的分支,以及一个在其他条件不满足情况下执行的默认分支。而 Policy 活动表示一系列规则。在 Windows Workflow Foundation 中,一条规则包括一个条件以及一个或一个以上引发的操作。可以将规则看作 If-Then-Else 语句,其中条件对应 If 块的 Boolean 临界条件,操作定义了 Then 和 Else 子句。让我们进一步了解各个活动,然后对它们进行比较。
Public Property MinimumLength() As Integer Get Return _minLength End Get Set(ByVal value As Integer) _minLength = value End Set End Property
图 4 针对 IfElse 活动的 Condition Editor(Click the image for a larger view)
当您试图读取 MinimumLength 的值时,运行时会结束调用属性的 get 存取器。该存取器能够回复私有成员 _minLength 的值。IfElse 活动中的最后分支可以没有条件。在这种情况下,它将作为 IF 工作流语句的 Else 分支。
指定条件的第二种方法是通过临时代码。在这种情况下,您可以为工作流类添加方法,例如:
Sub EvalCondition(ByVal sender As Object, ByVal e As ConditionalEventArgs) e.Result = ... ' Boolean value End Sub 该函数必须与接受对象和 ConditionalEventArgs 类并回复 void 的签名相匹配。ConditionalEventArgs 类的 Result 成员将设置为布尔值,代表条件的计算结果。
当您真正需要控制工作流的流动并连接各种工作块时,您应该使用 IfElse 活动组合。假如您所需要的仅仅是一个编程 If 语句序列,带有附加到分支的简单代码,那么最好使用 Policy 活动。Policy 活动是一个规则集合。与各规则相关的代码仅限于设置工作流属性,调用工作流方法或针对引用的程序集中的类型的静态方法。
活动与已排序的规则集合相关联,您可以通过编辑器定义规则。每条规则都有优先级和 Active 属性。这两种属性的组合确定了是否应当评估规则,以及采用哪种优先级。另外,规则还必须指定重估行为 —“Always(始终)”(默认值)或“Never(从不)”。假如设置为“Always”,规则将根据需要进行重估,否则只进行首次评估,以后无论工作流状态如何变化,也不再更改。
IF this.MinimumLength <= 8 THEN RefreshInternalState() 有谁能够知道 RefreshInternalState 方法将要做什么?该方法可能会触及涉及策略活动中其他规则的工作流属性。通过使用方法声明中的属性,您可以显式地表示该方法的行为:
<RuleWrite("PassWordLevel")> _ Public Sub RefreshInternalState() Me.PasswordLevel = 1 End Sub RuleWrite 属性表示方法将要修改指定的属性;同样,RuleRead 属性表示方法将要从指定的属性中进行读取。这样,就可以为运行时引擎提供明确清楚的信息以确保规则设置同步。
最后,您可以编写显式调用对涉及的属性进行更新的操作。例如:
IF this.MinimumLength <= 8 THEN RefreshInternalState() Update("PasswordLevel") 规则操作中的 Update 方法会计划对包含指定属性的所有规则进行重估。 QQRead.com 推出数据恢复指南教程 数据恢复指南教程 数据恢复故障解析 常用数据恢复方案 硬盘数据恢复教程 数据保护方法 数据恢复软件 专业数据恢复服务指南 循环和重复活动
这组活动提供了典型的 While 活动以及 Replicator 活动,这些活动与典型的 For 循环有些共同点。While 活动接受条件并在每次迭代开始时对该条件进行计算。假如条件为“true”,该活动将运行指定的子活动并重复直至条件为“false”。请注重在 While 主体内答应进行单一活动。因此,您可能要使用一个复合活动(如 Sequence 或 Parallel)在循环中执行多个活动。(在此处,使用术语“交错”可能比“并行”更加准确。因为没有涉及 Parallel 活动的并发,只有同一线程内的交错。) 与 Foreach 语句类似,Replicator 活动创建并执行指定的子活动的给定数量的实例。您可以只指定一个子活动,但答应使用复合或自定义活动。您不能通过声明性属性来控制迭代数。但是,您可以为初始化事件编写一个处理程序,并针对各个需要的实例,使用初始化数据填充 CurrentChildData 集合:
Sub replicator1_Initialized(ByVal sender As Object, ByVal e As EventArgs) Console.WriteLine("Initializing ...") replicator1.CurrentChildData.Add("You are #1") replicator1.CurrentChildData.Add("You are #2") replicator1.CurrentChildData.Add("You are #3") End Sub 前面所述的代码段规定了 Replicator 的子活动的三个实例的顺序,每个实例均使用给定的字符串进行初始化。请注重,假如您将 CurrentChildData 集合置为空,Replicator 将不运行任何子活动,并仅限于触发顶级事件,如 Initialized 事件和 Completed 事件。您可以使用对象(不一定是字符串)初始化子活动,包括自定义类的实例。Replicator 还包括标示各个子活动初始化和完成的事件。默认情况下,子实例按顺序运行,尽管通过设置 ExecutionType 属性,您可以选择并行执行。假如需要并行执行,在复制器开始并执行并行线程前,可以创建所有子活动实例。当以顺序模式执行时,只有当前一个活动结束时下一个活动才能被实例化。 假如没有通过 UntilCondition 属性设置全局条件,Replicator 将在所有复制完成后才结束,否则,将在 UntilCondition 为“true”时终止活动。值得注重的是,尽管在所有子活动已完成并且 UntilCondition 属性计算为“false”时活动将被挂起,Replicator 也从不通过类似 While 循环中的子活动进行循环。在对活动进行全局实例化后,在每个子活动完成后以及所有包括的活动都已完成后,将对 UntilCondition 进行计算。但是有时,假如条件计算为“true”,Replicator 将立即退出。
您可以将 ConditionedActivityGroup (CAG) 活动中的条件执行和循环混合在一起。CAG 包含一些子活动(可能是复合活动),并可运行这些活动,直至满足全局条件。基本上,CAG 组合了 While 和 IfElse 活动的行为。通过以下伪代码来表示内部逻辑:
While condition If child1.WhenCondition Then child1.Execute If child2.WhenCondition Then child2.Execute : If childN.WhenCondition Then childN.Execute End While 每个子活动都有 WhenCondition 属性。根据对指定条件的计算,可以在当前的迭代中运行或跳过活动。请注重,假如子活动没有 WhenCondition 集合,子活动将只能在第一次被执行,并在后续的迭代中被跳过。假如需要,可以根据状态变化的依存关系对所有条件进行计算。
Using ts As New TransactionScope ... ts.Complete End Using TransactionScope 对象保证在出现故障的情况下,事务既可以被提交也可以被回滚,更为重要的是,它可以确定您需要一个本地事务还是一个分布式事务,并登记所有必要的资源。当代码到达一个无法本地运行的点时,相应地,TransactionScope 提升至分布式事务处理协调器 (DTC)。实施 ITransaction 接口的所有对象可以随一个事务一起登记。该列表包括所有标准 ADO.NET 2.0 数据提供程序,并且 Microsoft 消息队列以兼容模式工作。
Dim service As New ExternalDataExchangeService runtime.AddService(service) Dim localService As New YourService() service.AddService(localService) 您可以配置 CallExternalMethod 活动以调用由本地服务实施的接口的方法。为什么 CallExternalMethod 仅限于调用已知接口的方法?原因在于活动不仅仅是代码执行者,而是旨在与 HandleExternalEvent 活动一起实施与本地服务的双向交流。借助 CallExternalMethod 活动,通过将 HandleExternalEvent 活动加入工作流,您可以调用服务方法,处理服务引发的事件。
总结
活动是工作流的构造块。通过在 Visual Studio 2005 设计器中撰写活动,您可以创建工作流解决方案。与 ASP.NET 中的服务器控件和 Windows Forms 中的控件类似,工作流活动是解决方案的精华所在并形成了开发人员的主要工具箱。Windows Workflow Foundation 提供了一些随机活动。在此,我要回顾一下涵盖事务、并行和条件执行、循环以及异常处理的活动。wf.netfx3.com 上提供了解一些其他免费活动。将它们挑出来!