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都正常執行了,如:
你也可以測試當該活動的子活動正在執行的時候,工作流程發生了異常,此時就會執行該活動的取消邏輯。在此我們就不再測試了。