尤尔根·利西斯
Microsoft Corporation
2006 年 2 月
适用于:
Windows Workflow Foundation (WF) Beta 2
Visual Studio 2005
摘要: 本文概述了 Windows Workflow Foundation(WF)中的规则引擎功能。 它描述如何在 WF 中使用条件和 RuleSet,并讨论规则集合的行为,包括前向链接和跟踪和跟踪。 (打印页 18 页)
注意 本文是使用 beta 2 编写的,将来可能需要进行一些更改才能使此操作适用于更高版本的 Windows Workflow Foundation。
内容
介绍
Windows Workflow Foundation 中的规则概述
规则评估
前向链接
前向链接控件
其他建模讨论
跟踪和跟踪
结论
有关详细信息
介绍
随着 Windows Workflow Foundation(WF)的可用性,Microsoft向 WinFX 开发人员平台引入了新的规则功能。 这些功能从推动活动执行行为的简单条件扩展到由功能齐全的转发链接规则引擎执行的复杂 RuleSet。
规则功能允许在整个业务流程范围内声明性建模应用程序逻辑单元。 规则引擎技术的示例方案包括订单验证、定价计算、促销强制执行、异常过程管理和声明判断和管理。
开发这项技术的关键目标是提供真正集成的工作流和规则体验。 在整个行业,规则和工作流通常都是非常不同的技术,通常由不同的供应商提供。 第三方规则引擎通常由工作流和业务流程管理(BPM)提供商嵌入或集成,但开发人员和管理体验显然不是无缝规则引擎。
借助 WF,Microsoft非常专注于在工作流和规则建模之间提供无缝开发人员体验,以便开发人员能够在工作流中的任何时刻轻松合并规则。 开发人员能够确定是否在工作流模型、规则或代码中为逻辑建模,而无需担心这些决策的集成影响。 但是,这并没有牺牲在工作流范围之外执行规则的能力。
第二个关键目标是为开发人员提供一个直接的模型,以便在定义规则时使用。 规则技术经常是一种利基技术,由一组高度专业化的规则专业人员使用。 虽然工具改进扩大了使用规则的个人集,但模型通常要求用户过于精通基础引擎的实现机制。 在向平台提供规则功能时,我们选择了一个模型,该模型可由广泛的 .NET 开发人员社区以及最终非开发人员使用。 虽然始终会有一定程度的领域专业知识(与任何技术一样),但我们的目标是让所有 .NET 开发人员能够快速提升规则模型,并轻松地将其纳入其应用程序中。
除了提供可接近的模型外,WF 还提供强大的评估引擎来支持复杂的规则方案,要求向前链接评估和精确的评估控制。 这以一种提供许多扩展点的方式提供,使开发人员能够在我们的平台上构建,并提供规则功能以支持各种方案。
本文档提供有关 WF 中提供的规则功能的技术简介以及可用功能及其用法的概述。 本文档末尾列出了可用于了解 WF 中的规则功能的其他资源。
Windows Workflow Foundation 中的规则概述
规则技术在 WF 中以两种主要方式公开,即活动条件和策略活动中的转发链接 RuleSet。 稍后将在文档中讨论转发链接;简言之,它是指一个规则的操作导致重新评估其他依赖规则的能力。
活动条件
以下四个随 WF 一起提供的活动使用条件:
- IfElseBranch
- 而
- 复制器
- ConditionedActivityGroup (CAG)
条件用于驱动这些活动的执行行为,例如,确定给定 IfElseBranch 是否将执行。 可以将条件指定为 CodeConditions,后者将在代码中具有配置的处理程序,也可以指定为 RuleConditionReference。 RuleConditionReference 将指向与工作流项目中工作流关联的 .rules 文件中的 RuleCondition 定义。 Visual Studio 中的体验如图 1 所示。
图 1. WF 规则条件创作
添加规则条件
以下是将规则条件添加到 IfElseBranch 活动(位于 IfElse 活动内)所涉及的步骤:
- 选择条件的活动(如 IfElseBranch 活动所示)时,“属性”网格中会显示 Condition 属性。
- Condition 属性的下拉列表允许用户选取 CodeCondition 或 RuleConditionReference。
- 如果选择 RuleConditionReference,则可以展开 Condition 属性以查看 ConditionName 和 Expression 属性。
- 提供条件名称后,选择 表达式 属性中的省略号以启动规则条件编辑器。 此编辑器允许开发人员使用类似于 intellisense 的支持在文本窗体中键入条件。 文本分析为 RuleCondition的关联对象模型表示形式。
- 选择“确定”
后, RuleCondition 定义将序列化为添加到项目的WorkflowName .rules 文件。
若要引用工作流上的字段或属性,可以键入 此字段。 编辑器。 键入点后,将显示类似于 Intellisense 的菜单,该菜单允许你在工作流上选取成员(也可以直接键入成员)。 也可以进行嵌套调用;例如,this.order.Total。 可以在引用的类型上调用静态方法,方法是键入类名后跟方法名称,就像在代码中一样。
以下关系运算符支持表达式:
- 等于 (“==” 或 “=”)
- 大于 (“>”)
- 大于或等于 (“>=”)
- 小于 (“<”)
- 小于或等于 (“<=”)
此外,可以使用以下算术运算符:
- 添加(“+”)
- 减去 (“-”)
- 乘法 (“*”)
- 除法(“/”)
- Modulus (“MOD”)
可以使用以下运算符组合/否定表达式:
- AND (“AND”, “&&”)
- OR (“OR”, “||”)
- NOT (“NOT”, “!”)
- 按位和 (“&”)
- 按位或 (“|”)
开发人员使用规则条件而不是代码条件的主要原因是规则条件成为模型的一部分,并且可以在运行时动态更新执行工作流实例。 规则条件的次要优势是,作为模型的一部分,可以在模型的基础上构建更复杂的工具,以提供额外的创作体验、依赖项管理、跨条件分析等。
策略活动
Policy 活动封装 RuleSet 的定义和执行。 RuleSet 是包含一组执行语义的规则集合。 规则反过来又是对工作流成员进行操作的 If-Then-Else 表达式。 该体验如图 2 所示,类似于规则条件所示。
图 2. WF RuleSet 创作
添加策略活动
若要为策略活动配置规则集,请执行以下步骤:
- 将策略活动从工具箱拖到工作流设计器上。
- 在 RuleSetReference 为 RuleSet 提供名称。
- 选择 RuleSet 定义 字段中的省略号将启动规则集编辑器。
- 编辑器在列表框中显示规则集合。
- 选择给定规则会显示其条件、Then 操作、Else 操作和一组附加属性。
- 与规则条件编辑器中一样,条件、Then 操作和 Else 操作以文本的形式输入,并解析为关联的对象模型表示形式;规则是针对工作流上的成员生成的。
- 选择 “确定” 会将 RuleSet 序列化为与工作流关联的 .rules 文件。
请注意,选择 RuleSetReference 属性中的省略号将启动编辑器,该编辑器允许用户选择现有的 RuleSet 或添加/重命名/删除 RuleSet,如图 3 所示。
图 3. WF RuleSet 浏览器
规则评估
RuleSet 中的每个规则都有一个优先级值,默认值为 0。 RuleSet 中的规则可以被视为按优先级值排序的排序集合。 WF 规则计算器单独评估规则,并根据规则的条件评估结果执行规则的操作。
可通过以下过程从概念上描述评估机制:
- 从活动规则列表开始。
- 查找最高优先级规则。
- 评估规则并根据需要执行其 Then/Else 操作。
- 如果规则的操作更新列表中上一个规则使用的字段/属性(优先级较高),请重新评估该上一规则并根据需要执行其操作。 请注意,仅重新评估具有特定依赖项的那些规则。
- 继续此过程,直到评估 RuleSet 中的所有规则。
让我们看一个简单的示例。 假设具有以下 RuleSet,其中 A、B等表示工作流上的数据。
规则 4 (优先级 = 4)
IF A = 15
THEN B = 5
规则 3 (P=3)
IF C = 5
THEN B = 10
规则 2 (P=2)
IF D = 2
THEN A = 15
规则 1 (P=1)
IF B = 5
THEN E = 7
假设你具有以下输入数据:
- A = 0
- B = 0
- C = 5
- D = 2
- E = 0
评估将按如下所示进行:
- 计算规则 4;它计算结果为 false,因为它没有 Else 操作,因此不会执行任何操作。
- Rule3 的计算结果为 true 并执行其操作,B = 10。 Rule4 不依赖于 B
的值,因此评估将转到 Rule2。 - Rule2 的计算结果为 true 并执行其操作,A = 15。
- 由于 Rule4 在其条件下使用 A 的值,因此将重新评估它。 计算结果为 true 并执行其操作,B = 5;规则 3 和 Rule2 不会重新计算,因为它们的条件不依赖于 A的值。以前的规则不依赖于 B的值,因此评估将转到 Rule1。
- Rule1 的计算结果为 true 并执行其操作,E = 7。
生成的数据集现在为:
- A = 15
- B = 5
- C = 5
- D = 2
- E = 7
前向链接
如前所述,链接基于规则中标识的依赖关系;更具体地说,规则的操作与其他规则的条件之间的依赖关系。 可以通过以下三种方式之一标识或声明这些依赖项:
- 含蓄
- 基于属性
- 明确
含蓄
隐式依赖项由引擎自动标识。 首次执行 RuleSet 时,将分析每个规则,以评估它在条件中读取的字段/属性,并在其操作中写入。 此操作是通过在条件中执行表达式和操作中的语句来完成的。 例如,假设有以下规则。
规则 1
IF this.subtotal > 10000
THEN this.discount = .05
规则 2
IF this.discount > 0
THEN this.total = (1-this.discount) * this.subtotal
引擎将评估规则,并确定规则 1 读取分类汇总字段并写入折扣字段。 规则 2 读取折扣和分类汇总字段,并将写入总计字段。 因此,规则 2 依赖于规则 1;结果是,每当规则 1 执行其 然后 操作时,引擎都会确保评估/重新评估规则 2。
请注意,依赖项在叶节点级别标识。 获取以下 RuleSet。
规则 1
IF this.order.Subtotal > 10000
THEN this.order.Discount= .05
规则 2
IF this.order.Discount > 0
THEN this.order.Total = (1-this.order.Discount) * this.order.Subtotal
规则 3
IF this.order.CustomerType = "Residential"
THEN ...
规则 1 和 2 之间仍会标识依赖项。 但是,规则 3 不会依赖于规则 1 或 2,因为两者都不会更新 CustomerType 属性。 换句话说,依赖项是在 CustomerType 属性级别标识的,而不是 Order 对象本身。
通过隐式链接,WF 对用户执行大部分必要的链接,以便用户不必显式建模更新,而且实际上,在大多数情况下,WF 不会意识到链接或需要链接。 我们预计,这将使大多数用户对复杂 RuleSet 的建模更加简单,并使得链接引擎的强大功能(主要是隐藏)的概念更加简单。 但是,为更复杂的特定方案提供了驱动链接、基于属性和显式的两种机制。
Attribute-Based
对于规则内的方法调用,确定性地评估发生的读取/写入会变得更加困难。 为了解决此问题,WF 提供了三个属性,这些属性可以应用于方法以指示其操作:
- RuleRead
- RuleWrite
- RuleInvoke
使用 RuleRead 属性对方法进行引用表示它读取指示的属性。 同样,RuleWrite 属性可用于指示方法更新给定字段或属性。 假设隐式节下的前两个规则被重写为以下内容。
规则 1
IF this.subtotal > 10000
THEN this.SetDiscount(.05)
规则 2
IF this.discount > 0
THEN this.total = (1-this.discount) * this.subtotal
然后,SetDiscount 方法可以按如下所示进行特性化,这样引擎就可以确定规则 2 依赖于规则 1,因为使用了折扣字段。
[RuleWrite("discount")]
void SetDiscount(double requestedDiscount)
{
...//some code that updates the discount field
}
RuleInvoke 属性可用于根据链接的方法调用来决定依赖项。 例如,假设对规则和方法进行了以下修改。
规则 1
IF this.subtotal > 10000
THEN this.SetDiscountWrapper(.05)
规则 2
IF this.discount > 0
THEN this.total = (1-this.discount) * this.subtotal
[RuleInvoke("SetDiscount")]
void SetDiscountWrapper(double requestedDiscount)
{
...
SetDiscount(requestedDiscount);
...
}
[RuleWrite("discount")]
void SetDiscount(double requestedDiscount)
{
}
规则 2 的条件调用 SetDiscountWrapper,后者又调用 SetDiscount,后者写入折扣字段。 RuleInvoke 属性允许引擎声明和检测此间接写入。
必须认识到,属性路径中引用的字段或属性引用与方法相同的类上的字段或属性,这不一定是传递给 RuleSet 以供执行的根对象。 例如,可以将 Order 类属性,如下所示。
public class Order
{
private double discount;
public double Discount
{
get { return discount;}
set { discount = value;}
}
[RuleWrite("Discount")]
void CalculateDiscount(double requestedDiscount, double weighting)
{
...//some code that updates the discount field
}
}
然后,可以在工作流中使用此类的实例,如下所示。
public class Workflow1 : SequentialWorkflowActivity
{
private Order discount;
...
}
然后,执行规则 2 将导致重新评估规则 1。
规则 1
IF this.order.Discount > 5
THEN ...
规则 2
IF ...
THEN this.order.CalculateDiscount( 5.0, .7)
有关使用属性的几个附加点:
- 属性指向 Owner 类上的字段/属性,而不是方法调用的参数。
- 还可以在规则属性中使用通配符。 例如,RuleWrite(“order/*”) 可用于指示方法修改了“order”字段引用的对象上的所有字段(在此示例中,该方法位于工作流本身上,而不是 Order 类)。 不过,通配符只能在路径末尾使用;RuleWrite(“*/Discount”) 等属性无效。
- RuleWrite(“order”) 等属性可用于引用类型,以指示引用已更改,例如,指示变量现在指向不同的 Order 实例。 除了测试实例本身的所有规则(例如,IF this.order == this.order2)之外,将假定变量上使用字段/属性的所有规则都会受到影响。
- 如果未指定任何方法属性,则默认行为是假定方法调用读取目标对象(调用该方法的对象)上的所有字段/属性,但写入其中的任何字段/属性。 此外,假定方法从传递给它的参数中读取,但假定该方法不会写入其中任何参数。 Out 和 ref 参数假定在规则操作中使用时写入。
明确
用于指示字段/属性依赖项的最后一种机制是通过使用 Update 语句。 Update 语句采用其参数,该字符串表示字段或属性的路径或表示字段/属性访问的表达式。 例如,可以将以下两个语句之一键入 RuleSet 编辑器,以便在工作流上 Customer 实例的 Name 属性上创建 Update 语句。
Update("this/customer/Name")
或
Update(this.customer.Name)
Update 语句指示规则写入指定的字段/属性。 这与规则中的字段/属性的直接集或调用具有字段/属性 RuleWrite 属性的方法的效果相同。
Update 命令还支持使用通配符。 例如,可以将以下 Update 命令添加到规则。
Update("this/customer/*")
这将导致重新评估 Customer 实例上任何属性的任何规则。 换句话说,将重新评估以下两个规则中的每一个。
IF this.customer.ZipCode == 98052
THEN ...
IF this.customer.CreditScore < 600
THEN ...
通常,用户不需要在大多数情况下为显式 Update 语句建模。 隐式链接应在大多数情况下提供所需的依赖项分析和链接行为。 方法归属应支持隐式链接无法识别依赖项的最普遍方案。 一般情况下,方法归因是用于指示依赖项而不是使用 Update 语句的首选方法,因为可以在该方法上识别一次依赖项,并跨使用该方法的许多不同的规则加以利用。 此外,在规则编写器和方法实现者是不同的个人(或工作在不同时间完成)的情况下,方法归因允许方法编写器(谁最了解代码)来识别方法的依赖项。
但是,在某些情况下,Update 语句将是适当的解决方案,例如,当字段/属性传递给工作流编写器无法控制的类上的方法时,因此无法按以下代码所示进行属性。
IF ...
THEN this.customer.UpdateCreditScore(this.currentCreditScore)
Update(this.currentCreditScore)
前向链接控件
向前链接是一个非常强大的概念,它允许原子规则组合到 RuleSet 中,而无需定义规则之间的依赖关系,甚至必须知道这些规则之间的依赖关系。
但是,在某些情况下,规则编写器可能希望能够更好地控制链接行为,特别是限制所发生的链接的能力。 这使规则建模器能够:
- 限制规则的重复执行,这可能会给出不正确的结果。
- 提高性能。
- 防止失控循环。
这两个属性在 WF 规则中促进此级别的控制:
- RuleSet 上的 链接行为 属性。
- 每个规则上的 重新评估行为 属性。
这两个值都可以在 RuleSet 编辑器中设置。
链接行为属性
RuleSet 上的 链接行为 属性有三个可能的值:
- 完整链接
- 显式链接
- 顺序
完整链接 选项是默认选项,提供目前所述的行为。 显式链接 选项关闭隐式链接和基于属性的链,并规定应仅对显式 Update 语句进行链接。 这使规则编写器可以完全控制哪些规则会导致重新评估。 通常,这用于避免循环依赖项导致过度(甚至失控)规则重新执行,或者通过消除不需要的多余的规则重新评估来提升性能,以提供 RuleSet 的功能完整性。
最后一个选项是 顺序。 此选项将导致引擎以严格线性方式评估规则。 每个规则将按优先级顺序计算一次和一次。 优先级较高的规则可能会影响优先级较低的规则,但反向规则不会如此,因为不会发生链接。 因此,除非规则中不存在依赖项,否则此选项将用于显式优先级分配。
重新评估行为属性
规则上的重新评估行为有两个可能的值:
- Always
- 从不
始终 是默认设置,并提供前面讨论的行为,即由于其他规则的操作,规则将始终根据链接重新评估。 从不,顾名思义,关闭此重新评估。 如果规则以前已执行任何操作,则会评估一次,但不会重新评估该规则。 换而言之,如果规则之前已评估并因此执行其 然后 或 Else 操作,则不会重新计算该规则。 但是,在 中执行空操作集合,然后 或 Else 操作不会将规则标记为已执行。
通常,此属性将用于规则级别,以防止由于规则在其自己的操作或其他规则上具有的依赖项而导致无限循环。 例如,以下规则将创建自己的无限循环,并且不需要重新评估来满足规则的功能要求。
IF this.shippingCharge < 2.5 AND this.orderValue > 100
THEN this.shippingCharge = 0
或者,如果规则旨在重新计算(但前提是 OrderValue 字段已更改),则用户可以将 RuleSet 上的链接行为设置为仅对显式 Update 语句(然后将这些 Update 语句添加到相关规则操作)。 当然,用户可以向此规则添加一个额外的谓词,用于检查 ShippingCost 的值尚未 0,但链接控件无需用户根据评估详细信息定义其规则,而不是其业务需求。
Halt 函数
作为最终控件,可以将 Halt 函数添加为规则操作(只需在编辑器中 或 Else 操作框)。 这会立即停止 RuleSet 执行并将控制权返回到调用代码。 当然,此函数的有用性不一定局限于链接控制方案。 例如,具有特定功能目标的 RuleSet 可以使用 Halt 函数在达到目标后进行短路执行。
其他建模讨论
基于优先级的执行
如前一部分所述,如果用户需要 RuleSet 的特定执行序列或该 RuleSet 中的规则子集,则可以使用规则上的优先级字段精确定义此序列。 这样做通常消除了链接的要求,用户甚至可以在这些方案中关闭链接。 我们发现,在许多情况下,只需提供显式执行排序即可满足规则依赖项。
不过,请务必注意,WF 中的转发执行机制为用户定义执行序列提供了一项功能,但不需要他们这样做。 在大多数情况下,转发链接行为使得不需要分配规则优先级来实现正确的 RuleSet 结果,因为关系由引擎自动管理,以确保满足规则依赖项。
遵循以下规则。
规则 1
IF this.Weather.Temperature < 50
THEN this.Drink.Style = "Latte"
规则 2
IF this.Drink.Style == "Latte"
THEN this.Snack.Style = "Scone"
ELSE this.Snack.Style = "Muffin"
在 WF 中,可以在规则 1 上提供更高的优先级,以便它首先执行。 这可确保在评估规则 2 之前设置 Drink.Style。
但是,不需要排序才能获得所需的结果。 假设先评估规则 2。 在这种情况下,Drink.Style 可能 null,也可以是另一种风格。 这将导致 Snack.Style 设置为 Muffin。 但是,在规则 1 执行并将 Drink.Style 设置为 Latte之后,规则 2 将重新评估,并将 Snack.Style 设置为 Scone。 本质上,用户可以选择听写排序,但在许多情况下不需要这样做。
集合处理
在某些情况下,可能需要针对集合中的所有项单独评估规则。 可以通过多种方式循环访问集合,但一种方法是采用如下规则模式:
规则 1 (优先级 = 2)
//always execute this rule once to create the enumerator
IF 1==1
THEN this.enumerator = this.myCollection.GetEnumerator()
规则 2 (优先级 = 1)
IF this.enumerator.MoveNext()
THEN this.currentInstance = this.enumerator.Current
规则 3-N (优先级 = 0)
.... //additional rules written against this.currentInstance
规则 N+1 (优先级 = -1)
// can be any condition as long as it is evaluated every time;
// this.currentInstance will be evaluated each time
//this.currentInstance changes, whereas
// "1==1" would only be evaluated once
IF this.currentInstance == this.currentInstance
THEN ...
Update("this/enumerator") //this will cause Rule 2 to be reevaluated
ELSE ...
Update("this/enumerator")
跟踪和跟踪
跟踪
执行 RuleSet 时,将跟踪事件发送到在已注册这些事件的主机上配置的跟踪服务,方法是向其跟踪配置文件添加 UserTrackPoint。 发送 RuleActionTrackingEvent,它提供计算的规则的名称以及条件评估结果(true/false)。 有关示例,请参阅 SDK 中的 RuleActionTrackingEvent 示例。
可以通过跟踪活动执行来隐式跟踪活动的规则条件评估结果。
描图
通过将以下内容添加到应用程序配置文件,可以将其他 RuleSet 评估信息发送到日志文件。
<configuration>
<system.diagnostics>
<switches>
<add name="Rules" value="Information"/>
</switches>
</system.diagnostics>
</configuration>
以下信息将发送到日志文件:
-
条件依赖项信息:
- 示例: 规则“ReturnNumberOfStops”条件依赖项:“this/currentFlight/OutboundFlight/NumberOfStops/”
-
操作副作用信息:
- 示例: 规则“ReturnNumberOfStops”THEN side-effect:“this/currentFlight/Score/”
-
链接关系:
- 示例: 规则“ReturnNumberOfStops”THEN 操作触发规则“Approved Hocke”
-
RuleSet 执行:
- 示例: 规则:“执行 RuleSet FlightRuleSet”
-
条件评估:
- 示例: 规则:评估规则“SetDefaultScore”的条件
-
条件评估结果:
- 示例: 规则:评估为 True 的条件
-
操作执行:
- 示例: 规则:评估规则“SetDefaultScore”的 THEN 操作
所有跟踪消息当前都在“信息”级别定义,因此应在配置文件中指定信息级别或详细级别以查看规则跟踪。
结论
WF 提供了灵活的规则功能,可通过多种不同的方式利用这些功能来支持各种方案。 从简单的活动条件到复杂的前向链接 RuleSet,该技术使你可以将规则支持无缝集成到工作流中。 此外,还可以利用工作流外部的规则引擎向任何 .NET 应用程序提供规则功能。
此功能集允许新开发人员轻松地将简单的规则合并到工作流中,同时仍提供丰富性和可扩展性来支持更高级的 RuleSet 和应用程序方案。 本文档与下一部分中引用的资源相结合,应帮助 WF 规则的开发人员了解这项技术并快速提高工作效率。
有关详细信息
-
许多文档和指向网络广播和实验室的链接。
-
- 外部 RuleSet Toolkit— 提供了如何从工作流程序集外部化规则的示例。
- RuleSet 分析- 一种工具,用于分析规则集,以查找规则与数据之间的关系。
- Excel中的
规则 - 提供了如何在工作流外部独立使用规则的示例。 此外,还演示如何以编程方式创建通过 Excel 中的决策表创作的规则。
SDK 示例
- IfElseWithRules— 显示 IfElse 活动(在 \Technologies\RulesAndConditions 下)上使用 RuleCondition。
- DynamicUpdateChangingRules— 演示如何使用动态更新 API 更改正在运行的工作流实例上的 RuleCondition(\Technologies\RulesAndConditions)。
- SimplePolicy— 演示如何使用 API 定义简单的 RuleSet 和策略活动(\Technologies\Activities\Policy)。
- AdvancedPolicy— 定义更复杂的 RuleSet(\Technologies\Activities\Policy)。
- RuleActionTrackingEventSample— 演示如何在跟踪提供程序(\Technologies\Tracking)中捕获规则评估结果。
-
- 有关 WF 规则或 WF 的一般问题,请访问此论坛。
关于作者
Jurgen Willis 是 Windows Workflow Foundation 团队的项目经理,负责规则引擎技术和规则驱动活动。 在加入Microsoft之前,Jurgen 为财富 500 强公司设计并实施了集成和流程管理解决方案。