网络安全 频道

Windows 工作流活动技术概览

然而,作为一个整体设置的规则要进行正向推理。简而言之,正向推理是指一个规则的操作导致其他相关规则被重估的能力。例如,对另一个规则测试的字段的值进行更新操作需要对所涉及的规则进行重估(除非对该规则的重估被禁用)。正向推理有三种类型。 隐式推理表示运行时引擎将判断哪些字段被一些操作修改了,然后自动对它们进行重估。只要操作显式地作用于属性,这种机制即可成功。如果有如下操作,情况又会怎样:

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 方法会计划对包含指定属性的所有规则进行重估。

  循环和重复活动

  这组活动提供了典型的 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 集合,子活动将只能在第一次被执行,并在后续的迭代中被跳过。如果需要,可以根据状态变化的依存关系对所有条件进行计算。

  在 UntilCondition 返回“true”并立即取消所有当前正在执行的活动后,CAG 活动将终止。如果没有指定条件,当因为没有设置条件或者条件计算为“false”而没有子活动运行时,CAG 也将结束。

  同步块

  涉及交错活动的顺序工作流都会对共享成员的访问进行系列化。然而,操作是不同的。当两个或两个以上以交错方式运行的序列用到 Parallel 活动时,操作是不同的。请看一下图 5。While 活动包含两个序列块,然后,序列块又将 Parallel 活动和代码活动联系在一起。在内部,Parallel 活动有四个块,每个块都对定义为工作流类成员的数字执行数学运算。Parallel 活动的四个分支以交错方式执行。(每一次在工作流实例中只有一个线程。该线程在 Parallel 活动的分支间来回切换。)跨任务同步又如何呢?默认情况下,子活动内部运行的每一段代码都进行对共享成员的直接访问。

图 5 平行任务
图 5 平行任务(Click the image for a larger view)

根据图 5 所示的简单架构,可能会出现每个分支都作为一个原子操作来运行的情况。这纯属巧合,运行严格依据各操作的复杂性和持续时间。如果每个分支由多个活动组成,情况会怎样?SynchronizationScope 提供了声明性和明确的同步存取建模方法,它可以实现对一组活动中一个给定工作流实例内的共享状态进行同步存取。

  SynchronizationScope 活动内运行的工作流部分是一种不能中断的原子操作。此处没有事务语义,SynchronizationScope 活动中包含的操作不能回滚。在所有基于活动(这些活动具有并行执行路径,如 Parallel、Replicator 和 CAG)的解决方案中,SynchronizationScope 活动起着关键作用。

  图 6 可以帮助您快速体验 SynchronizationScope 活动的作用,该图是图 5 中工作流的修改版本。blockMultiply 活动对延迟交错的两个代码块进行计数。blockDivide 活动包含一个未同步的代码块。如果您将 blockMultiply 的内容放到同步范围之外,blockDivide 将可能在 blockMultiply 的延迟阶段执行。根据要进行的更新的种类不同,这可能会成为一个严重问题。SynchronizationScope 活动可确保工作流部分的连续性。

图 6 平行任务与同步范围
图 6 平行任务与同步范围(Click the image for a smaller view)

  异常处理

  正如其他基于 .NET 的应用程序一样,工作流能够引发和捕获异常。特别是,您可以使用 Throw 活动来引发一个特定的异常。Throw 活动需要几个设置 — 要引发的异常的类型,存储异常对象实例以进行进一步自定义的工作流类成员。只要在工作流项目中引用了类型,您就可以使用自定义的异常类型。

  要捕获工作流活动引发的异常,您要添加 FaultHandler 活动。工作流设计器提供了一个用于您添加的错误处理程序的容器。每个处理程序一定是某个工作流的一部分,一旦捕获异常,该程序即执行。添加 FaultHandler 活动后,您可以定义要捕获的异常的类型。您可以通过 Fault 属性访问异常对象。值得注意的是,要可视化错误处理程序,您必须在 Visual Studio 2005 设计器中切换视图并通过单击设计器视图底部的选项卡列表来选择“View Faults(查看错误)”选项卡。

  事务

  .NET Framework 2.0 包括一个轻松而有效处理事务的对象 — 无论参与对象的数目和类型以及范围如何,也无论事务是本地的还是分布式的。该对象被命名为 TransactionScope,一般情况下,您可以根据如下模式进行使用:

Using ts As New TransactionScope
 ...
 ts.Complete
End Using

  TransactionScope 对象保证在出现故障的情况下,事务既可以被提交也可以被回滚,更为重要的是,它可以确定您需要一个本地事务还是一个分布式事务,并登记所有必要的资源。当代码到达一个无法本地运行的点时,相应地,TransactionScope 提升至分布式事务处理协调器 (DTC)。实施 ITransaction 接口的所有对象可以随一个事务一起登记。该列表包括所有标准 ADO.NET 2.0 数据提供程序,并且 Microsoft 消息队列以兼容模式工作。

  值得注意的是对于分布式事务,TransactionScope 和企业服务之间存在一些差别。TransactionScope 属于专门针对基于 .NET 的应用程序而设计的事务框架 — System.Transactions。在内部,System.Transactions 命名空间的类有时会以为 DTC 和 COM+ 委派一些工作作为结束。为什么在这一点上 TransactionScope 至关重要?TransactionScope Windows Workflow Foundation 活动仅仅是 TransactionScope .NET 类实例的一个工作流包装程序。

  当您为工作流添加 TransactionScope 活动时,您可以设置要完成的事务的超时时间,并设置所需的隔离级别。事务范围内组合的所有活动形成了能够实现典型 ACID 架构的工作单位。在所有子活动都成功完成后将提交事务,工作流继续进行到下一步。如果在范围内引发异常,TransactionScope 活动自动回滚。编写事务性工作流并不要求您显式地处理提交和回滚语义 — 如果您要提交事务和引发异常来中止事务,您只需顺其自然。该活动将可以轻松管理其他任何事情。

  请注意,您不能嵌套两个或两个以上的 TransactionScope 活动。同样地,您不能使用 Suspend 活动挂起事务内的工作流。然而,您可以通过 Listen 或 EventHandlingScope 活动,将事件处理程序整合到事务中。在这种情况下,工作流主机应当包括持久性服务,否则,如果工作流试图将它的状态保存为空闲状态,会引发异常。 此外,相关的活动,如 CompensatableTransactionScope 还支持补偿。补偿是在有后续业务预期的情况下,从逻辑上撤消已完成的事务的过程。补偿与回滚不同,因为它是一种当工作流中发生违反规则的情况时,取消已成功完成和提交的事务所产生的影响的有效方法。在两个帐户间进行资金划转的事务是一个典型的回滚示例。第一个调用将资金从一个帐户中取出,第二个调用将相同数额的资金划转至另一个帐户。只要数据库支持两阶段提交模型,如果在事务中引发异常,回滚可恢复一致的状态。

  设想一下一个订单处理工作流,其中一个事务被用于通过信用卡进行支付。第一步,首先从信用卡中提取资金来支付货款。然后,在交易成功完成后,该货物不能再被销售。如果违反了业务规则,需要按照合适的规定对交易结果进行补偿 — 一般是将资金划入签帐卡。

  通过右键单击 CompensatableTransactionScope 活动,您可以切换到事务的“补偿”视图并添加所有补偿事务影响所需的活动。在图 7 中,OrderScope 事务与补偿活动规定相关联,该规定要求在出现业务异常的情况下,应将已提取的资金退回。正如我前面谈到的,工作流中的异常是通过异常处理程序捕获的。对于某一特定异常(如 ProductDiscontinued),您可以调用一个 Compensate 活动,该活动已绑定到其影响作用已被取消的事务活动。一般情况下,Compensate 活动会触发适用于任何可被补偿的活动(即,适用于实施 ICompensatableActivity 接口的活动)的补偿机制。与 CompensatableTransactionScope 一起,CompensatableSequence 也实施了本接口并能够用于非事务性的补偿情况。不过,您也可以编写支持补偿的自定义活动。

图 7 事务与补偿活动
图 7 事务与补偿活动(Click the image for a larger view) 

  调用其他代码

  此外,还有一些活动可调用和执行代码。这些活动包括:Code、InvokeWorkflow、InvokeWebService 和 CallExternalMethod。Code 活动最灵活,可以表示您在工作流某一点插入的自定义代码块。Code 活动触发您在工作流中处理的 ExecuteCode 事件,并能使其运行您所需要的代码。代码将包含在工作流中并与其一起进行编译。Code 活动可以调用外部程序集,只要您在 ExecuteCode 事件处理程序中加入所有能够加载程序集和选择方法的必要代码。

  InvokeWorkflow 活动可以引用工作流和异步调用工作流。您可以传递输入参数,但要注意 InvokeWorkflow 活动要在被启动的工作流开始执行之前完成。您无法将当前工作流的执行与外部工作流的执行同步,也不能处理当前工作流中的输出参数。

  InvokeWebService 活动可以通过代理类同步调用 Web 服务方法。使用 Code 活动并调用 Web 服务,可以对活动的行为进行模拟。

  最后,CallExternalMethod 活动可用于调用本地服务方法。本地服务是对于实施以 ExternalDataExchange 属性修饰的接口的工作流可用的任何类。另外,代表本地服务的类必须作为外部数据交换服务添加到工作流运行时。

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 上提供了解一些其他免费活动。将它们挑出来!http://netadmin.77169.com/HTML/20061128002000_3.html

0
相关文章