MOSS多级审批工作流【StateMachine版】v1.1
去年我发布过一个MOSS多级审批工作流,采用顺序工作流模式开发;后来又做了一些改进,用ConditionedActivityGroupActivity取代了繁复的WhileActivity+IfElseActivity嵌套,但仍然是顺序工作流。
在第二篇文章的末尾我曾写道:“审批这样的流程并不适合用顺序工作流来实现,用WF的另外一种工作流-状态机工作流会更好”,为什么这样说呢?
我们已经知道,顺序工作流的执行过程是一个连续的步骤,从开始到结束,虽然我们可以利用While这样的循环活动让工作流看起来往回去执行了几步,但是这样的后果就是一张难以理解的流程图和复杂的执行逻辑。
真实世界的工作流程是灵活的,往往不是一条线走到底的,中间可能包含这许多决策,每个决策都可能让流程走向另外一个方向。所以包含人类参与的工作流其实是一个决策推动的流程,把它抽象到工作流中,就成了“事件驱动工作流”,也就是状态机工作流(StateMachine Workflow)。
状态机工作流由一系列状态(State)组成,每个状态中又可以包含一系列事件的处理程序。状态机工作流总是停留在一个状态中,等待必要的事件被触发,然后跳转到新的状态。
那么现在再来看看这个多级审批工作流的原始流程图:
下面是用状态机实现后的流程图:
你会发现,状态机工作流的流程图和我们最初的流程图相当接近,无论是流程块还是之间的连线。如果再和之前用顺序工作流实现后的流程图对比一下,那么以后你在遇到人类参与的工作流时,一定不会考虑用顺序工作流实现了。
下面简要的说明一下状态机工作流的开发要点:
1.如何规划状态?
在MOSS的状态机工作流中,我们一般这样规划一个状态:

在状态初始(StateInitializationActivity)时创建任务(CreateTaskActivity),在状态结束(StateFinalizationActivity)时删除任务(DeleteTaskActivity)。而在初始化和结束之间,我们可以添加多个事件驱动(EventDrivenActivity),EventDrivenActivity的作用是接收并处理事件(比如任务被修改的事件,OnTaskChangedActivity),然后可以根据事件的处理结果跳转到其它状态(SetStateActivity),你可以将SetStateActivity理解为各个状态之间的连接线。
2.如何实现Task3和Task4的并发?
注意在最初的流程图中,Task3和Task4是两个并列的任务,在这个审批流程的Sequence版实现中,我们当然选择用ParallelActivity来实现并发,在StateMachine中我们仍然可以这样做,不过如果要将Task3和Task4安排成两个状态,我们就得在ParallelActivity的两个分支中都添加一个SetStateActivity并指向相应的State。
但是这时候你会吃惊的发现,虽然每条分支都执行了,但只有最后一条分支中的SetStateActivity正确的执行了跳转。
因为一个EventDrivenActivity只能跳转到一个StateActivity,所以我们需要其它方法来实现Task3和Task4的并发。
我的方法是将Task3和Task4集成到一个状态里,先在状态初始时创建两个任务,然后添加两个几乎一模一样的EventDrivenActivity来分别处理两个任务被修改的事件,下面是这个EventDrivenActivity的子活动组成:

在处理完任务被修改的事件后,我会将此任务标记为“已完成”,并记录其审批结果;接着,利用IfElseActivity判断两个任务是否都被标记为“已完成”,如果还有任务没有完成,就不做任何操作,如果两个任务都已经完成,就再根据它们的审批结果来决定跳转到哪个状态。
3.为什么把删除任务的活动添加到了EventDrivenActivity内部而不是StateFinalizationActivity内部?
这样做是因为我想在任务被处理后马上删除它,但StateActivity总是等到执行SetStateActivity时才会执行到StateFinalizationActivity,而上面我们已经实现了两个任务都完成后才发生跳转,所以如果将DeleteTaskActivity添加到StateFinalizationActivity的话,就做不到实时删除任务了。
4.为什么要在EventDrivenActivity内部添加IfElseActivity?
答案是为了实现直到两个任务都完成后才发生跳转。
但是,这样做的后果就是我不得不在每次处理完任务之后都添加这个IfElseActivity,好在我们的流程只有两个并发的任务,如果有三个、五个甚至更多呢?这种判断方法就显得非常麻烦,而且会让流程结构变得臃肿,难道就没有更好的方法吗?希望和大家一起探讨这个问题,我也会在下一篇文章中介绍一种取代这种频繁利用IfElseActivity进行判断的方法。
OK,以上就是这个多级审批工作流(StateMachine版)的实现要点,欢迎大家共同交流探讨。
源码下载:点击下载(Visual Studio 2008)




Windie Chai @ 豆瓣
windiechai @ Twitter
windiechai @ 新浪微博
搬个板凳好好学习学习
不错!楼主的1.0版本就已经很赞了:)
处理状态的并发,实际上单纯的状态机模型是不支持的,不管是采用Parallel+SetState或者是其它的SetState组合的方法,最终只有最后一个执行的SetState真正起作用,根本原因在于状态机模型只支持唯一的当前活动状态。
这个问题看来必须采用一些变通的办法,楼主的帖子又给出了一种思路。
我在msdn的forum上请教过这个问题,微软专家给出的解决方案是采用调用子流程的方法,楼主不妨一试。
@赤脚小子
下一篇文章中我将分享一种方法来在同个State中��现所有的EventDriven完成后进行操作。
不知道和你所说的是否有共同点,呵呵,到时候再探讨。
@笑煞天
期待ing:)
我要加紧学习了
楼主发的太及时了
又见此马甲~~~
@风中的猪儿
兄台也在园子里有地儿啊。呵呵。
好好来学习学习
实在很感谢作者的无私,其实我想发表一些很有见地的看法的,但是实在是苦无水平啊,不过我会先努力搞清SharePoint Server 2007是什么的。
@赵俊
共同探讨学习嘛。
对于这个2008的项目下面这些组件是不是也都要安装啊?都是免费的吗?
SharePoint Server 2007
InfoPath 2007
Visual Studio 2005 Extensions for Windows Workflow Foundation
ECM Starter Kit for Visual Studio 2005
@赵俊
对这个项目来说,你需要:
SharePoint Server 2007
Visual Studio 2008
InfoPath 2007
.NET Framework 3.0
带“2005”字样的工具统统丢掉吧,呵呵。
这么快就回复哪?好快的身手,吓到我了!
@赵俊
嘿嘿,今天特别照顾。
–引用————————————————–
Windie Chai(笑煞天): @赵俊
对这个项目来说,你需要:
SharePoint Server 2007
Visual Studio 2008
InfoPath 2007
.NET Framework 3.0
带“2005”字样的工具统统丢掉吧,呵呵。
——————————————————–
对这个项目需要的软件���没有下载地址,干脆连下载地址一起提供了吧,我搜索了一下发现需要的软件都好大,而且不是免费软件,这样一来又是一笔很大的学习开支,在商业项目中使用的话花精力还要花钱。
@赵俊
呃,这个,恕我无能为力,传播盗版是不对滴~~
其实不把���版用在商业开发上面就好了,毕竟盗版对中国的工农业生产现代化建设方面带来了不可磨灭的贡献。
@赵俊
那你想办法下载MSDN版做研究吧,嘿嘿。
我好像发现这两个软件(SharePoint Server 2007,InfoPath 2007)是office 2007里面的两个软件,都好大,这样的话发布的时候是不是客户机器上面也要装啊?office 2003里面没有这两个软件吗?
@赵俊
这个,兄台对Office Server完全没有接触吗?
建议先了解一下,再研究开发也不迟。
LZ:请教以下工作流如何实现:即
一份文档发出后,可能要多个部门审核,但具体那些部门审核这时还不确定,
等到文控人员勾选审核部门后���确定,并且只有这些选定的部门全部审核通过,
此文件才算PASS(这些部门的审核是无先后次序的),否则只要有其中一个部门REJECT,则不通过返回发出部门。
谢谢!
学习!!!
@dlfsystem
三种方式可以参考:
1.直接发给文控人员,让他转交。
2.文控人员在关联表单中设置���审批部门,这样做的话,一旦工作流被关联(关联表单被设置),整个流程的步骤就确定了,不可再变了。
3.启用修改,让文控人员随时修改工作流。
不明白任务的意义,为什么在状态开始的时候要创建,结束后又要删除
@黑颈
因为任务已经完成了,没有必要继续存在来使列表变庞大了,当然你也可以不删除,或者移动到归档列表等。
如果不删除,还得进行权限的控制,以免以后又被修改等等,所以本文仅仅是一个sample。
郁闷!下了半天下了一个OfficeServerwithSP1.exe文件说安装失败,可���不是这个,是不带SP1补丁的哪个,不知道不使用这些软件能不能实现工作流方法。
–引用————————————————–
Windie Chai(笑煞天): @dlfsystem
<br/>三种方式可以参考:
<br/>1.直接发给文控人员,让他转交。
<br/>2.文控人员在关联表单中设置好审批部门,这样做的话,一旦工作流被关联(关联表单被设置),整个流程的步骤就确定了,不可再变了。
<br/>3.启用修改,让文控人员随时修改工作流。
——————————————————–
谢谢你,可能第三种方式更可行,但如何:启用修改,这样是不是可以
做个Infopath表单,让文控每次发行文件时,选择需要审核部门,但这时
如何实现这种动态工作流呢?另外,关联表单是什么呢?
@dlfsystem
不知道你说的���态工作流是什么意思。
关联表单是指你在给一个列表关联工作流的时候需要填写的表单,该表单一般由网站管理人员填写,用于初始化工作流的一些值。
自己来抢第五百条评论!
–引用————————————————–
Windie Chai(笑煞天): @dlfsystem
不知道你说的动态工作流是什么意思。
关联表单是指你在给一个列表关联工作流的时候需要填写的表单,该表单一般由网站管理人员填写,用于初始化工作流的一些值。
——————————————————–
因为每份文件的发行所经过的审批部门都不同,不可能��所有的可能的审批组合
都分别做对应的工作流,所以现在的想法是,先设计一个部门的审批工作流,然后由文控勾选某份文件的的一些审批的部门后,由根据指定的这N个部门复制N份
审批工作流。。。
@dlfsystem
只要流程一样就可以用一个了。
研究了一下office server,发现它的内存占用率实在是太大了,安装了以后,我的内存占用都在1G以上(我的机器就只有1G内存),而且office server只能安装在window 2003 sp1以上的系统里面,对XP不支持。
@赵俊
兄台的发现是正常的,要不怎么叫做Server呢。
闲的时候思索下Windows的设计思想,再想想我们用的WF,我们已经站在巨人的肩膀上了,可以看得更远,做出的东西也更好咧。
赞个先…
@pccai
同感!
–引用————————————————–
Windie Chai(笑煞天): @dlfsystem
只要流程一样就可以用一个了。
——————————————————–
楼主:你所说的:只要流程一样就可以用一个了。但具体如何实现,给个思路
如何! 再次谢谢
@dlfsystem
流程一样,只需要指���不同的审批部门,不就OK了。
–引用————————————————–
Windie Chai(笑煞天): @dlfsystem
流程一样,只需要指定不同的审批部门,不就OK了。
——————————————————–
这点好理解,关键是:文控勾选的这些部门每次是不确定,如何保存与某份文件
对应的部门代码呢?部门用户又如何在审核某份文件时,调出与这份文件对应的
部分代码?
我因为才接触Sharepoint 2007不久,是个初学者,请不吝赐教!
@dlfsystem
呃,这是件很容易的事情,既然给了文控人员控制权,那么他就有相对应的任务(表单),这些数据就保存在任务中,在工作流代码中,非常容易捕获任务被修改的事件,也非常容易为任务设置或者读取数据。
–引用————————————————–
Windie Chai(笑煞天): @dlfsystem
呃,这是件很容易的事情,既然给了文控人员控制权,那么他就有相对应的任务(表单),这些数据��保存在任务中,在工作流代码中,非常容易捕获任务被修改的事件,也非常容易为任务设置或者读取数据。
——————————————————–
真不好意思,可不可以给段代码做点参考!
问一句博主,注册过gac的工作流,再想删除,如何操作
@zhouche9961
工作流也是一个feature,卸载feature就可以了。
博主,我们要开发一个文档评审系统,比较复杂,请问您在什么地方,能否给���做顾问
@芒果
在北京,你可以通过博客侧边栏的Email和我联系。
楼主,我下载了你这个例子,但为什么在我机子上打��开infopath?报此错误:
表单模板: file:///C:\Documents%20and%20Settings\Administrator.HYZ\桌面\StateMachineApproval\StateMachineApproval\Init.xsn
表单模板试图访问计算机上的文件和设置。但是该表单模板不是完全受信任的,所以 InfoPath 无法向其授予对这些文件和设置的访问权限。若要以完全信任方式运行表单,必须使用证书安装表单或使用证书对其进行数字签名。
要如何做才可以?在调试项目时报另外一个错误:
错误 1 找不到位于 http://windie/ 的 Web 应用程序。请确认正确键入了此 URL。如果此 URL 需要提供现有内容,则系统管理员可能需要添加到指定应用程序的新请求 URL 映射。
但我双击它没有定位到哪里错误,又要如何处理呢?
请问这个怎么部署到Sharepoint站点上呢,前面的版本都有一个批处理文件,怎么这个里面没有了呢?用什么部署到站点上?
@Jachnicky
1.InfoPath表单的编辑方法是右键单击选���“设计”
2.想要调试当然要修改部署的目标站点URL,在VS2008的项目菜单中有SharePoint调试选项
@Buddy
你仍然可以用那个批处理文件,只需要修改一些参数即可。
或者直接用vs2008打开,修改部署站点url后发布。
下一篇的链接呢
请给出来
@virus
拜托,你看一下这一篇的发布时间,再到日志列表里找不就知道下一篇了吗?这很复杂吗?
算了,还是我给你吧:http://www.cnblogs.com/xiaoshatian/archive/2008/07/22/1248102.html
看了楼主的例子 帮助很大 先感谢一下
我有个问题就是,我填写第一个审批表单提交后,每个人都有权限看到第二级任务,我只想有权限的人(比如自己选择的上级)能看到这个任务,只想有权限的人去审批,如何去修改添加���个权限呢?要写什么程序呢?小弟初学,弄了两天了毫无进展,楼主能不能帮个忙 谢谢
问个比较低级的问题,与这个工作流关联的文档库或列表需要设置什么条件么?
麻烦楼主帮帮忙看看这个问题:我建了一个列表(列表里就一个标题栏)与这个状态机工作流关联。运行以后在列表中新建个项目的时候就报错:“值不能为空。参数名: s” 。报错的语句是:“XmlTextReader xtr = new XmlTextReader(new System.IO.StringReader(workflowProperties.InitiationData));”。
@鹏飞这旮旯根据错误可以判断,你使用了初始表单,那么启动工作流时候,应该先显示此表单。但自动启动的工作流是不会显示此表单的,所以你的InitiationData永远是空的。也就是说,自动启动工作流和初始表单是不能一起使用的,这应该算是SharePoint的一个bug。
明白了,谢谢楼主
学习了,谢谢楼主!
Windie,你好,感谢分享这样的好东西我在我的测试机器上部署了该工作流,可是不知道为什么启动流程,提交后,总是出现“由于内部错误,此工作流未能启动。”的错误,不知道是否哪里没有设置正确?
@重金属检查Log。
[...] 在上一篇文章《MOSS多级审批工作流【StateMachine版】》中,有这样一个情景,我创建了两个任务,并且要等到这两个任务都完成后,根据其结果进行一些操作。在这一部分,我遇到一个问题,如何并行的处理这两个任务呢? [...]