WF提供的标准活动中有很多复合活动,这些复合活动可以添加子活动比如:SequenceActivity,ParallelActivity,ReplicatorActivity等。这些活动都有特定的用途,如果WF提供的标准活动都不满足我们的需要的时候,我们就要自己开发一个复合活动。
活动的状态模型
活动在他的生命周期中有六种状态。 这些状态分别为 Initialized、Executing、Canceling、Closed、Compensating 和 Faulting。下图摘自MSDN中说明活动之间状态的转换关系:
1.红色实线表示工作流运行时引擎负责将活动从 Initialized 状态转换到 Executing 状态,或从 Closed 状态转换到 Compensating 状态。
2.黄色实线表示父活动负责将子活动从 Executing 状态转换到 Closed 状态。 如果您创建自定义复合活动,则必须亲自进行处理。
3.蓝色实线表示工作流运行时引擎负责将活动从 Executing、Canceling 或 Compensating 状态转换到 Faulting 状态。
4.黄色虚线表示工作流运行时引擎负责将活动从 Canceling 状态、Compensating 状态或 Faulting 状态转换到 Closed 状态。
5.仅当所有子活动都处于 Closed 或 Initialized 状态时,才能关闭活动。
活动执行上下文(AEC)
AEC是在宿主应用程序调用 Start 方法时为活动创建的执行环境。AEC可以使用ExecuteActivity 或CancelActivity方法来执行或取消 子活动。 也可以通过 CloseActivity方法 方法来关闭自己。 这些是仅有的父活动可以通过 AEC 控制的执行状态更改。 所有其他活动状态都是由工作流运行时引擎控制的。
关于活动状态和AEC的在《WF本质论》的前几章中有非常详细的讲解,推荐大家去看看。
开发一个自己的SequenceActivity
WF中所有的复合活动都继承子CompositeActivity,要开发一个基本的复合活动一般有以下几个步骤:
1.重写基类的Execute方法,在该方法中安排第一个子活动的执行,如果没有子活动要执行就返回Closed状态。还需要注册状态更改事件。
2.处理状态更改事件,在此我们判断是否还有子活动要执行,如果有就继续执行,如果没有就调用AEC的CloseActivity来关闭活动。
3.重写基类的Cancel方法,处理如当有异常发生的时候来执行的取消逻辑。
下面我们就开发一个自己的SequenceActivity,我们建立一个顺序型工作流项目,新建一个自定义活动,代码如下:[Designer(typeof(SequentialActivityDesigner))]
public partial classCarySequenceActivity: CompositeActivity,
IActivityEventListener<ActivityExecutionStatusChangedEventArgs>
{...}
该活动继承自CompositeActivity活动和接口IActivityEventListener<ActivityExecutionStatusChangedEventArgs>,IActivityEventListener接口用于监听活动的执行状态事件的更改的相关信息。
1.我们首先重写基类的Execute方法,代码如下:
protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext) { if (this.EnabledActivities.Count == 0) { return ActivityExecutionStatus.Closed; } else { this.EnabledActivities[0].RegisterForStatusChange(Activity.ClosedEvent, this); executionContext.ExecuteActivity(this.EnabledActivities[0]); } return ActivityExecutionStatus.Executing; }
2.实现IActivityEventListener接口的OnEvent方法,代码如下:
public void OnEvent(object sender,ActivityExecutionStatusChangedEventArgs e) { ActivityExecutionContext context = sender as ActivityExecutionContext; if (context == null) { throw new ArgumentException("Expected sender to be an ActivityExecutionContext","sender"); } e.Activity.UnregisterForStatusChange(Activity.ClosedEvent, this); Int32 activityIndex = this.EnabledActivities.IndexOf(e.Activity); if (activityIndex == this.EnabledActivities.Count - 1) { context.CloseActivity(); } else { activityIndex++; if (this.ExecutionStatus == ActivityExecutionStatus.Executing) { this.EnabledActivities[activityIndex].RegisterForStatusChange(Activity.ClosedEvent, this); context.ExecuteActivity(this.EnabledActivities[activityIndex]); } else if (this.ExecutionStatus == ActivityExecutionStatus.Canceling) { if (CancelProcessing(context)) { context.CloseActivity(); } } } }
3.重写基类的Cancel方法,代码如下:
protected override ActivityExecutionStatus Cancel(ActivityExecutionContext executionContext) { if (CancelProcessing(executionContext)) { return ActivityExecutionStatus.Closed; } else { return ActivityExecutionStatus.Canceling; } } private Boolean CancelProcessing(ActivityExecutionContext executionContext) { Boolean isTimeToClose = true; foreach (Activity activity in this.EnabledActivities) { if (!isTimeToClose) { break; } switch (activity.ExecutionStatus) { case ActivityExecutionStatus.Executing: executionContext.CancelActivity(activity); isTimeToClose = false; break; case ActivityExecutionStatus.Canceling: case ActivityExecutionStatus.Compensating: case ActivityExecutionStatus.Faulting: isTimeToClose = false; break; case ActivityExecutionStatus.Initialized: case ActivityExecutionStatus.Closed: break; default: break; } } return isTimeToClose;
}
4.这样我们就完成一个基本的复合活动,该活动的功能和WF提供的标准活动SequenceActivity相似,如果你现在使用
Reflector反编译一下WF本身提供的SequenceActivity活动的源代码,你会发现我们的处理方式是几乎相同的。我们
就来测试一下该活动,生成项目后,我们在工作流设计器上拖入CarySequenceActivity活动,向该活动内放几个
CodeActivity活动,如下图:
5.运行工作流,我们可以看出几个CodeActivity都正常执行了,如下图:
你也可以测试当该活动的子活动正在执行的时候,工作流发生了异常,此时就会执行该活动的取消逻辑。在此我们就不再测试了。