Service Pack 2 阻止“更改时启动”工作流自行启动
Service Pack 2 阻止“更改时启动”工作流自行启动
大家好!我是 SharePoint Designer 的撰稿者 Stephen,很高兴与大家再次进行交流。我想向大家介绍随适用于 Office SharePoint Server 2007 和 Windows SharePoint Services 3.0 的 Service Pack 2(该链接可能指向英文页面) 提供的一个修补程序。此修补程序影响在 SharePoint Designer 2007 中设计的工作流。然后,我将介绍如何使用两个工作流(而不是一个)有针对性地创建工作流循环。
在安装 Service Pack 2 之前,可以非常轻松地设计自行触发和创建无限循环的工作流。例如,请考虑以下情形:
1) 工作流在项目更改时启动。
2) 工作流更新(或更改)当前项目(例如,使用“设置当前项目中的域”(Set Field in Current Item) 操作)。
3) 因为工作流更改了项目,所以它自行触发。
因此,如果您具有发送电子邮件然后更新当前项目的“更改时启动”工作流,您可能会很快在收件箱中收到几百封电子邮件。
在服务器上安装 Service Pack 2 后,项目更改时启动的工作流不能再通过更改/更新当前项目自行触发。不可能出现以下无限循环情形:
然而,很多用户已经设计出真正利用无限循环的工作流。例如,可以设计一个“更改时启动”工作流,它针对某个任务项无限循环并且在该任务标记为完成之前始终发送每日提醒。该工作流通过更新“计数器”列自行触发,向列表中添加“计数器”列只是为了实现这一目的。并且该工作流具有在满足某一条件时停止或“中断”工作流的规则 — 在本例中,工作流在任务“状态”=“已完成”时停止,而不更改当前项目。在安装 SP2 之后,实际上会破坏该工作流,因为它无法自行触发。
SP2 并不阻止无限循环(这可能非常有用),而是在您必须设计两个(或更多)相互触发的“更改时启动”工作流之前重新创建有效内容。两个通过更新/更改当前项目相互触发的“更改时启动”工作流属于“共同递归”情形:
此外,使用相互触发的几个较短工作流实现基于状态的工作流很常见。例如,您可能具有一个列表,并且一个“状态”域和多个“更改时启动”工作流附加到该列表中。所有这些工作流在最后都包含一个更新“状态”域的步骤。因此一个工作流通过更新“状态”触发其他多个工作流,然后这些工作流查看“状态”域中的值以确定它们应该继续运行还是停止。此基于状态的工作流也属于“共同递归”情形,因为一个工作流通过更改/更新当前项目启动其他很多“更改时启动”工作流。Service Pack 2 不阻止这种类型的基于状态的工作流,这种工作流依赖共同递归。
重述
· 在安装 SP2 之前,单个“更改时启动”工作流可能会通过更新当前项目从而自行触发进入无限循环。
· 在安装 SP2 之后,“更改时启动”工作流可以通过更新当前项目触发其他任意“更改时启动”工作流,但是“更改时启动”工作流不能自行触发。因此,不阻止共同递归情形,包括使用很多较小的“更改时启动”工作流实现基于状态的工作流的任何情形。
· 在此提醒大家,绝对不能通过使“创建时启动”工作流在当前列表中创建项目来创建无限循环。每个工作流都包含“我无法启动的工作流”属性 — 此属性用于阻止创建项目时启动的工作流循环。
· 进一步提醒大家,上述所有情形仅涉及附加到单个列表或库的工作流。从不阻止“更改时启动”工作流或“创建时启动”工作流在跨列表情形中无限循环。
在安装 Service Pack 2 之前创建循环
本节提供一个示例,以说明在安装 SP2 之前单个“更改时启动”工作流如何利用无限循环。安装 SP2 之后,该工作流将不能自行触发,因此下一节提供一个示例,以说明如何使用两个单独的工作流创建循环。
假定您具有名为“工作组任务”(Team Tasks) 的任务列表,您希望设计一个在任务标记为完成之前每天发送提醒的工作流。
首先,向列表中添加名为“计数器”(Counter) 且默认值为 0 的列。
您需要在列表表单(“新建项目”(New Item)、“编辑项目”(Edit Item))中隐藏“计数器”(Counter) 列,以便只有工作流可以对其进行访问/更新。首先,在列表设置页上,单击“高级设置”(Advanced Settings),然后允许管理内容类型。
在列表设置页上,单击每种内容类型,并在下一页上单击“计数器”(Counter) 列。隐藏“计数器”(Counter) 列。对列表中的每种内容类型执行此操作。
创建和隐藏“计数器”(Counter) 列以使其不显示在表单中之后,即可开始设计工作流。
“每日提醒”(Daily Reminder) 工作流应该在创建或更改项目时启动。
首先进行检查以确定两个问题:(1) 如果任务已标记为完成,则工作流停止。此规则在任务最终标记为完成时“中断”循环。(2) 如果任务未完成,则工作流检查截止日期是否是将来的日期(晚于今天)。如果是,则工作流会暂停,直至到达截止日期,因为您不想在到达截止日期后发送提醒。
第二步是再次检查任务是否已完成(以防在上一步骤中工作流在到达截止日期之前暂停,并且任务在此期间完成)。如果任务仍未完成,则工作流暂停一天。
第三步是再次检查工作流暂停期间任务是否已完成;如果是,则工作流停止。
如果任务尚未完成,则工作流 (1) 发送电子邮件提醒;(2) 通过查阅“当前项目”(Current Item)/“计数器”(Counter) 域设置 CurrentCount 变量;(3) 将 CurrentCount 增加 1 并将该值存储到 NewCount 变量中;(4) 将“计数器”(Counter) 列设置为存储在 NewCount 变量中的值。
每次工作流运行时,此步骤基本上都会将“计数器”(Counter) 列递增 1,因此您可以查看“计数器”(Counter) 列,以确定发送了多少提醒。最重要的是,此步骤最后的“设置当前项目中的域”(Set Field in Current Item) 操作就是对当前项目所作的“更改”,从而导致工作流自行触发和创建循环。
在安装 Service Pack 2 之后创建循环
在安装 SP2 之后,仍可以实现这种循环效果,但需要设计两个相互触发(共同递归)的工作流,而不是单个自行触发的工作流。
在这里您将使用 (1) 使计数递增的“计数器”(Counter) 工作流 (2) 实际发送提醒邮件的“工作线程”(Worker) 工作流。
第一个工作流 —“计数器”(Counter) 工作流
与上面的示例相同,您需要在列表中创建默认值为 0 的“计数器”(Counter) 列,允许管理内容类型并对列表中的每种内容类型隐藏此域。
两个工作流的设计都需要第二个列,“发送邮件”(SendMail),该列充当“工作线程”(Worker) 工作流的标记。默认值必须为“否”(No),否则,对任务项目的任何更改都将导致发送提醒邮件。
“计数器”(Counter) 工作流将在创建或更改项目时启动。
第一步是检查任务状态 – 如果任务已完成,则 “计数器”(Counter) 工作流停止。
如果任务的截止日期是将来的日期(晚于今天),则第二个步骤会暂停,直至到达截止日期,因为您不想在任务到达截止日期后发送提醒。
第三步是再次检查任务是否已完成,以防在上一步骤中工作流暂停期间完成任务。如果任务仍未完成,则工作流暂停一天。
最后一步是再次检查状态以确定在前一天暂停时任务是否已完成。如果未完成,则工作流通过以下方式更新当前项目 (1) 将“计数器”(Counter) 列的值递增 1 (2) 将“发送邮件”(SendMail) 标记设置为“是”(Yes)(默认值为“否”(No))。
第二个工作流 —“工作线程”(Worker) 工作流
前面的“计数器”(Counter) 工作流将在更新(更改)当前项目后结束。这些更新会触发“工作线程”(Worker) 工作流,该工作流设置为在项目更改时启动。
“工作线程”(Worker) 工作流直接检查“发送邮件”(SendMail) 标记是否设置为“是”(Yes);如果是,则工作流会发送提醒邮件并将标记设置回“否”(No)。
如果将“发送邮件”(SendMail) 标记设置为“否”(No),这一更改会触发前面的“计数器”(Counter) 工作流。“计数器”(Counter) 工作流和“工作线程”(Worker) 工作流相互触发,以发送每日提醒,直到任务标记为完成。
此外,您可以让“工作线程”(Worker) 工作流在“计数器”(Counter) 列达到特定值(比如 5 个提醒)时升级任务通知,而不是创建无限循环。以下步骤根据提醒计数执行不同的分支。计数达到 5 时,工作流向经理发送邮件,您可以将经理的电子邮件地址“硬编码”到“发送电子邮件”操作或者使用工作流查找功能从列表中检索。
还可以让“工作线程”(Worker) 工作流在发送特定数目的提醒后将任务重新分配给不同的个人或组。对于该步骤,工作流将任务重新分配给由负责跟踪此类升级任务的工作组成员组成的 SharePoint 组。
如果您想在计数达到特定数目后结束循环,还要确保向“计数器”(Counter) 工作流(而不是“工作线程”(Worker) 工作流)的第一个步骤中添加一个分支。该分支在“计数器”(Counter) 列达到 6 时将停止循环。
希望这些内容会对您有所帮助。
—Stephen
这是一篇本地化的博客文章。请访问 Service Pack 2 prevents an on-change workflow from starting itself 以查看全文
!-->