關於動態更新
在開發工作流時,我們會在工作流設計器中通過拖拽活動,設置屬性等等來設計我們的工作流,我們 希望我們在設計時定義好的工作流在運行時是不變的。但在實際中我們往往需要在運行時來改變工作流 的架構,例如我們已經定義好的流程在沒有結束時我們需要增加一個流程點,這個時候我們就需要使用 動態更新來現實。在WF中我們也可以對正在運行的工作流實例添加刪除活動,修改活動,規則條件等。 當動態更新應用到工作流實例上時,只影響當前的工作流實例。其他的和將來的都不受影響,仍然使用 原始的工作流定義。
動態更新不適合要進行整體更改的情況,因為這將導致工作流與原始設計原則產生極大差別。 在此 類情況下,應設計一個新的工作流,而不是對正在運行的實例進行更改。動態更新不必重新編譯和重新 啟動工作流。
何時進行動態更新
我們可以從工作流的執行線程內部和外部對正在運行的工作流實例進行動態更新。 在內部,我們可 以使用CodeActivity,自定義活動等來實現,由於工作流運行在單一的線程上,所以我們執行動態更新 的時候不會有其他的活動在執行。 在外部,我們實現動態更新就有嚴格規定,主要有以下狀態可以在宿 主程序中進行動態更新:
1. 工作流實例創建完成,但是沒有開始。
2. 工作流實例是掛起狀態,沒有恢復。
3. 工作流實例是空閒狀態。
我們可以在WorkflowRuntime的WorkflowCreated,WorkflowSuspened,WorkflowIdled事件中來完成 動作更新。WorkflowCreated事件在workflowRuntime.CreateWorkflow方法調用後引發,使用使用 SuspendActivity可以使工作流轉到掛起狀態,引發WorkflowSuspened事件。使用DelayActivity或 HandleExternalEventActivity時工作流會進入Idle狀態,引發WorkflowIdled事件。
動態更新的一般步驟
我們通過以下幾個步驟進行動態更新:
1.所有對運行中工作流實 例的建議的更改必須使用WorkflowChanges對象進行。首先我們要創建一個該類的實例,構造函數中需要 需要傳遞被更改的工作流實例的根活動。如果你是使用內部實現動態更新的方式,你直接傳遞this關鍵 字就可以了。如果你是在外部宿主程序中,你需要使用workflowinstance的GetWorkflowDefinition方法 來獲取工作流實例的根活動。
2.WorkflowChanges對象被創建後。該對象的TransientWorkflow屬 性返回該工作流實例的克隆版本,我們會對該克隆版本進行更改,然後將更改應用到運行中的工作流實 例。
3.我們需要找到你要添加或刪除活動的父活動,可以使用CompositeActivity的Activities 屬性或是使用GetActivityByName方法來確定父活動,然後使用Add或Insert方法來添加或插入新的活動 。移除活動使用remove方法。
4.使用WorkflowChanges的Validate方法來驗證,如果有錯誤會返 回ValidationError對象集合。
5.驗證通過後就可以更新了,如果是在外部實現動作更新需要調 用workflowinstance對象的ApplyWrokflowChange方法,內部的話就調用當前對象的 ApplyworkflowChanges方法。
阻止動態更新
順序和狀態機工作流都有一個 DynamicUpdateCondition屬性,如果你沒有設置該屬性工作流一直允許動態更新,當你設置了該屬性後 ,當你在調用ApplyWorkflowChanges方法時就會去計算,如果為true則允許進行動態更新,否則就會拋 出異常。
動態更新實例
下面我們分別使用在工作流內部和外部兩種方式來舉例說明,首 先我們建立一個順序型工作流控制台程序,工作流設計如下圖:
工作流代碼如下:
public sealed partial class CaryDynamicUpdateWorkflow: SequentialWorkflowActivity
{
public CaryDynamicUpdateWorkflow()
{
InitializeComponent();
}
private void beforeSequence_ExecuteCode(object sender, EventArgs e)
{
Console.WriteLine("beforeSequence執行了");
}
private void afterSequence_ExecuteCode(object sender, EventArgs e)
{
Console.WriteLine("afterSequence執行了");
}
private void IsUpdate(object sender, ConditionalEventArgs e)
{
e.Result = true;
}
}
我們會在運行時給該工作流中的sequenceActivityContainer添加 一個自定義活動PrintActivity,該自定義活動僅僅向控制台輸出一條語句,代碼如下:
public partial class PrintActivity : System.Workflow.ComponentModel.Activity
{
public PrintActivity()
{
InitializeComponent();
}
protected override ActivityExecutionStatus Execute (ActivityExecutionContext executionContext)
{
Console.WriteLine("自定義 Print活動");
return base.Execute(executionContext);
}
}
1.宿主程序中,首先我們在workflowRuntime的WorkflowCreated事件中執行動態更新.代 碼如下:
static void workflowRuntime_WorkflowCreated(object sender, WorkflowEventArgs e)
{
WorkflowChanges wc = new WorkflowChanges (e.WorkflowInstance.GetWorkflowDefinition());
CompositeActivity sequenceContainer = wc.TransientWorkflow.GetActivityByName
("sequenceActivityContainer") as CompositeActivity;
if (sequenceContainer != null)
{
PrintActivity print = new PrintActivity();
sequenceContainer.Activities.Add(print);
ValidationErrorCollection errors = wc.Validate();
if (errors.Count == 0)
{
try { e.WorkflowInstance.ApplyWorkflowChanges(wc); }
catch (Exception ex)
{
Console.WriteLine(" 引用動態更新異常:{0}", ex.Message);
}
}
else
{
foreach (ValidationError error in errors)
{
Console.WriteLine("驗證錯誤:" + error.ToString ());
}
}
}
}
2.運行程序後得到如下 圖結果:
3.從上圖可以看出我們自定義的PrintActivity活動在運行時添加到了工作流實例當中,以上 我們是在宿主程序中執行動態更新的,我們也可以在工作流內部來完成,例如我們將動態更新的代碼放 到我們重寫的Initialize方法中,我們只要將如下代碼做更改即可:
WorkflowChanges wc = new WorkflowChanges(e.WorkflowInstance.GetWorkflowDefinition());
try { e.WorkflowInstance.ApplyWorkflowChanges(wc); }
改為:
WorkflowChanges wc = new WorkflowChanges(this);
try { this.ApplyWorkflowChanges(wc); }
運行程序你 可以得到和上面一樣的結果。4.如果你將工作流的DynamicUpdateCondition屬性設為false,此時做動態 更新時會拋出異常,如下圖: