Windows Workflow Foundation中实现人工活动的demo,按照XPDL规范的实现
在XPDL规范中,一个人工参与的活动有以下特性:活动任务的多实例(根据活动上指定的参与者,分配活动任务,活动任务我们称为工作项),工作项的分配策略(ALL所有参与者分配和Radom随机挑选分配,当然还有更多的资源模式,因为是是demo就不实现了),活动的完成策略(ALL所有工作项完成活动才完成和ANY任意工作项完成即完成),工作项执行模式(并行和串行)。
开始我的描述,下图是封好的组合活动,整个组合活动暴露的属性有:参与者(是个集合,可以自己定义组织模型接口,用户、岗位、用户组、组织等)、分配策略、完成策略、执行模式、预警规则等。
我们一一来看组合活动中的每个活动的作用:
1、FindParticipant活动传入参与者列表和分配策略,经过对策略的不同处理(动态的参与者需要从上下文中获取),返回最终确定的参与者。
2、ApprovalReplicator活动是ReplicatorActivity,这个是实现活动任务多实例的关键。将计算获得的参与者列表作为ReplicatorActivity的InitData,参与者列表的数量会决定整个ReplicatorActivity块的执行次数,每次会起单独的线程(通过观察ActivityExecutionContext的ID与父活动的不一样得知,异步线程的Context都是自己管理的),每个线程的初始数据即为具体的一个参与者。根据工作项执行模式是并行的还是串行的来设置ReplicatorActivity的ExecutionType属性。ReplicatorActivity的四个事件都很有用,为了初始数据和支持策略的实现,这里不赘述。再多说一句,WF设计器好像对IList类型的属性支持不好,实现中我都是手写代码绑定的这类参数,应该是个Bug。
3、SingleApproval是封的组件活动,因为ReplicatorActivity里只能包含一个活动,所以必须封一下。
4、CreateWorkItem根据线程拥有的参与者,在数据库中创建工作项。工作项概念在WF中没有,估计WF就不是为人工活动设计的。我们就将其设计为业务数据,可以在数据库部署上与WF默认提供的数据库分离。
5、LintenForApproval+WaitComplete配合实现流程对用户完成工作项的等待。这里要注意的关键点是CorrelationToken的运用,目的是分清楚来自与宿主程序的完成工作项的事件到底要发给哪个线程。WF的这个设计还是与Biztalk一致的,需要有创建CorrelationToken的活动(本例中是CreateWorkItem),后续的活动(本例中是WaitComplete)标记为Follow这个CorrelationToken。CorrelationToken的OwnerActivityName的设置也是很关键的点,这种多线程的场景中,如果这个属性设置为SingleApproval就坏事了,这样每个线程的CorrelationToken还是区分不出来,这里的技巧是设为/Parent,由运行时指定为父活动,WF引擎是支持的。还有一点要提的是,需要使用CorrelationToken的这种活动引用的用户接口必须加上CorrelationParameter特性,这个Lab中都有,不赘述了。
6、UserSolve活动就是根据用户完成工作项的执行情况(宿主程序在事件参数中传入用户执行结果)。
7、DelayActivity根据传入的预警信息生成等待的时间,DefaultSolve即完成预警信息中指定的动作。
8、还差一点就是完成策略还没有提到,这个是通过ReplicatorActivity的UntilCondition来实现的,只要这个条件计算的结果是true,那么整个ReplicatorActivity就结束,而丢弃其他未完成的线程,每个线程的结束都会触发这个条件计算的执行。剩下的策略规则就不难实现了,根据不同的场景堆代码吧。
以上的组合活动来实现人工活动的要点有:
1、处理好ReplicatorActivity活动
2、Listen活动+HandlerExternalEvent活动的配合,CorrelationToken的设置
完成这个demo后还觉得这样实现太过于啰嗦,真想用代码直接写个HumanActivity。对于上面的两个关键点的用代码实现的设想:
1、ReplicatorActivity,我们用代码根据参与者列表起几个Thread的问题。
2、Listen活动+HandlerExternalEvent活动,用WF的消息队列+书签的方式就可以搞定了,这个有疑问请看我前一篇博文。CorrelationToken我们写代码想这么搞怎么搞,哈哈!
开始我的描述,下图是封好的组合活动,整个组合活动暴露的属性有:参与者(是个集合,可以自己定义组织模型接口,用户、岗位、用户组、组织等)、分配策略、完成策略、执行模式、预警规则等。
我们一一来看组合活动中的每个活动的作用:
1、FindParticipant活动传入参与者列表和分配策略,经过对策略的不同处理(动态的参与者需要从上下文中获取),返回最终确定的参与者。
2、ApprovalReplicator活动是ReplicatorActivity,这个是实现活动任务多实例的关键。将计算获得的参与者列表作为ReplicatorActivity的InitData,参与者列表的数量会决定整个ReplicatorActivity块的执行次数,每次会起单独的线程(通过观察ActivityExecutionContext的ID与父活动的不一样得知,异步线程的Context都是自己管理的),每个线程的初始数据即为具体的一个参与者。根据工作项执行模式是并行的还是串行的来设置ReplicatorActivity的ExecutionType属性。ReplicatorActivity的四个事件都很有用,为了初始数据和支持策略的实现,这里不赘述。再多说一句,WF设计器好像对IList类型的属性支持不好,实现中我都是手写代码绑定的这类参数,应该是个Bug。
3、SingleApproval是封的组件活动,因为ReplicatorActivity里只能包含一个活动,所以必须封一下。
4、CreateWorkItem根据线程拥有的参与者,在数据库中创建工作项。工作项概念在WF中没有,估计WF就不是为人工活动设计的。我们就将其设计为业务数据,可以在数据库部署上与WF默认提供的数据库分离。
5、LintenForApproval+WaitComplete配合实现流程对用户完成工作项的等待。这里要注意的关键点是CorrelationToken的运用,目的是分清楚来自与宿主程序的完成工作项的事件到底要发给哪个线程。WF的这个设计还是与Biztalk一致的,需要有创建CorrelationToken的活动(本例中是CreateWorkItem),后续的活动(本例中是WaitComplete)标记为Follow这个CorrelationToken。CorrelationToken的OwnerActivityName的设置也是很关键的点,这种多线程的场景中,如果这个属性设置为SingleApproval就坏事了,这样每个线程的CorrelationToken还是区分不出来,这里的技巧是设为/Parent,由运行时指定为父活动,WF引擎是支持的。还有一点要提的是,需要使用CorrelationToken的这种活动引用的用户接口必须加上CorrelationParameter特性,这个Lab中都有,不赘述了。
6、UserSolve活动就是根据用户完成工作项的执行情况(宿主程序在事件参数中传入用户执行结果)。
7、DelayActivity根据传入的预警信息生成等待的时间,DefaultSolve即完成预警信息中指定的动作。
8、还差一点就是完成策略还没有提到,这个是通过ReplicatorActivity的UntilCondition来实现的,只要这个条件计算的结果是true,那么整个ReplicatorActivity就结束,而丢弃其他未完成的线程,每个线程的结束都会触发这个条件计算的执行。剩下的策略规则就不难实现了,根据不同的场景堆代码吧。
以上的组合活动来实现人工活动的要点有:
1、处理好ReplicatorActivity活动
2、Listen活动+HandlerExternalEvent活动的配合,CorrelationToken的设置
完成这个demo后还觉得这样实现太过于啰嗦,真想用代码直接写个HumanActivity。对于上面的两个关键点的用代码实现的设想:
1、ReplicatorActivity,我们用代码根据参与者列表起几个Thread的问题。
2、Listen活动+HandlerExternalEvent活动,用WF的消息队列+书签的方式就可以搞定了,这个有疑问请看我前一篇博文。CorrelationToken我们写代码想这么搞怎么搞,哈哈!