共用方式為


動態更新

動態更新提供一種機制,讓工作流程應用程式開發人員更新持續性工作流程實例的工作流程定義。 這可以是實作 Bug 修正、新需求,或因應非預期的變更。 本主題提供 .NET Framework 4.5 中介紹的動態更新功能概觀。

若要將動態更新套用至保存的工作流程實例, DynamicUpdateMap 會建立 ,其中包含運行時間的指示,描述如何修改保存的工作流程實例以反映所需的變更。 建立更新地圖之後,將其套用到所需的已保存工作流程實例。 套用動態更新之後,可以使用新的更新工作流程定義繼續工作流程實例。 建立及套用更新對應需要四個步驟。

  1. 準備動態更新的工作流程定義
  2. 更新工作流程定義以反映所需的變更
  3. 建立更新地圖
  4. 將更新映對應套用至所需的持久化工作流程實例

備註

步驟 1 到 3 涉及更新地圖的建立,可獨立於套用更新的過程中執行。 常見的案例是工作流程開發人員會離線建立更新對應,然後系統管理員稍後會套用更新。

本文提供將新活動新增至已編譯 Xaml 工作流程之持續性實例的動態更新程式概觀。

準備動態更新的工作流程定義

動態更新程式的第一個步驟是準備所需的工作流程定義以進行更新。 這是藉由呼叫 DynamicUpdateServices.PrepareForUpdate 方法並傳入要修改的工作流程定義來完成。 此方法會驗證工作流程樹狀結構,以識別所有物件,例如需要標記的公用活動和變數,以便稍後與修改過的工作流程定義進行比較。 完成時,工作流程樹狀結構會複製並附加至原始工作流程定義。 建立更新對應時,工作流程定義的更新版本會與原始工作流程定義進行比較,並且會根據差異產生更新對應。

若要準備動態更新的 Xaml 工作流程,它可能會載入 至 ActivityBuilder,然後將 ActivityBuilder 傳遞至 DynamicUpdateServices.PrepareForUpdate

備註

如需有關使用序列化工作流程和 ActivityBuilder的詳細資訊,請參閱 將工作流程和活動序列化至和從 XAML

在下列範例中,一個由MortgageWorkflow組成的定義(包含數個子活動)會載入到Sequence中,然後準備進行動態更新。 方法傳回之後, ActivityBuilder 會包含原始工作流程定義以及複本。

// Load the MortgageWorkflow definition from Xaml into
// an ActivityBuilder.
XamlXmlReaderSettings readerSettings = new XamlXmlReaderSettings()
{
    LocalAssembly = Assembly.GetExecutingAssembly()
};

XamlXmlReader xamlReader = new XamlXmlReader(@"C:\WorkflowDefinitions\MortgageWorkflow.xaml",
    readerSettings);

ActivityBuilder ab = XamlServices.Load(
    ActivityXamlServices.CreateBuilderReader(xamlReader)) as ActivityBuilder;

// Prepare the workflow definition for dynamic update.
DynamicUpdateServices.PrepareForUpdate(ab);

更新工作流程定義以反映所需的變更

工作流程定義準備好進行更新之後,就可以進行所需的變更。 您可以新增或移除活動、新增、移動或刪除公用變數、新增或移除自變數,以及變更活動委派的簽章。 您無法移除執行中的活動,或變更執行中委派的簽章。 這些變更可以使用程式代碼,或在重新裝載的工作流程設計工具中進行。 在下列範例中,一個自定義的VerifyAppraisal 活動被新增到由上一個範例中的 MortgageWorkflow 組成的 Sequence 主體中。

// Make desired changes to the definition. In this example, we are
// inserting a new VerifyAppraisal activity as the 3rd child of the root Sequence.
VerifyAppraisal va = new VerifyAppraisal
{
    Result = new VisualBasicReference<bool>("LoanCriteria")
};

// Get the Sequence that makes up the body of the workflow.
Sequence s = ab.Implementation as Sequence;

// Insert the new activity into the Sequence.
s.Activities.Insert(2, va);

建立更新地圖

一旦準備更新的工作流程定義已修改,即可建立更新對應圖。 若要建立動態更新地圖,會呼叫 DynamicUpdateServices.CreateUpdateMap 方法。 這會傳回 DynamicUpdateMap,其中包含執行階段修改已儲存的工作流實例所需的資訊,以便以新的工作流定義載入並繼續。 在下列範例中,為了上一個範例中修改的MortgageWorkflow定義,將建立一個動態地圖。

// Create the update map.
DynamicUpdateMap map = DynamicUpdateServices.CreateUpdateMap(ab);

此更新映射可以立即用來修改已保存的工作流程實例,或通常會先儲存,然後在稍後套用這些更新。 儲存更新地圖的方法之一是將它序列化成檔案,如下列範例所示。

// Serialize the update map to a file.
DataContractSerializer serializer = new DataContractSerializer(typeof(DynamicUpdateMap));
using (FileStream fs = System.IO.File.Open(@"C:\WorkflowDefinitions\MortgageWorkflow.map", FileMode.Create))
{
    serializer.WriteObject(fs, map);
}

DynamicUpdateServices.CreateUpdateMap 傳回時,將會移除在呼叫 DynamicUpdateServices.PrepareForUpdate 中新增的複製工作流程定義和其他動態更新資訊,而已修改的工作流程定義已準備好儲存,以便稍後在繼續更新的工作流程實例時使用。 在下列範例中,修改過的工作流程定義會儲存至 MortgageWorkflow_v1.1.xaml

// Save the modified workflow definition.
StreamWriter sw = File.CreateText(@"C:\WorkflowDefinitions\MortgageWorkflow_v1.1.xaml");
XamlWriter xw = ActivityXamlServices.CreateBuilderWriter(new XamlXmlWriter(sw, new XamlSchemaContext()));
XamlServices.Save(xw, ab);
sw.Close();

將更新映射套用至所需的已保存的工作流程實例

建立更新地圖之後,可以隨時套用。 您可以使用由DynamicUpdateMap傳回的DynamicUpdateServices.CreateUpdateMap實例立即執行,也可以稍後使用更新地圖的已儲存副本來執行。 若要更新工作流程實例,請將它載入WorkflowApplicationInstance,然後使用WorkflowApplication.GetInstance。 接下來,使用更新的工作流程定義和所需的 WorkflowApplication建立 WorkflowIdentity 。 這 WorkflowIdentity 可能與用來持久化原始工作流程的不同,通常是為了反映持久化的實例已經過修改。 WorkflowApplication建立之後,它會使用多載的WorkflowApplication.Load載入,以接受DynamicUpdateMap為參數,然後呼叫WorkflowApplication.Unload進行卸除。 這會套用動態更新,並保存更新的工作流程實例。

// Load the serialized update map.
DynamicUpdateMap map;
using (FileStream fs = File.Open(@"C:\WorkflowDefinitions\MortgageWorkflow.map", FileMode.Open))
{
    DataContractSerializer serializer = new DataContractSerializer(typeof(DynamicUpdateMap));
    object updateMap = serializer.ReadObject(fs);
    if (updateMap == null)
    {
        throw new ApplicationException("DynamicUpdateMap is null.");
    }

    map = (DynamicUpdateMap)updateMap;
}

// Retrieve a list of workflow instance ids that corresponds to the
// workflow instances to update. This step is the responsibility of
// the application developer.
List<Guid> ids = GetPersistedWorkflowIds();
foreach (Guid id in ids)
{
    // Get a proxy to the persisted workflow instance.
    SqlWorkflowInstanceStore store = new SqlWorkflowInstanceStore(connectionString);
    WorkflowApplicationInstance instance = WorkflowApplication.GetInstance(id, store);

    // If desired, you can inspect the WorkflowIdentity of the instance
    // using the DefinitionIdentity property to determine whether to apply
    // the update.
    Console.WriteLine(instance.DefinitionIdentity);

    // Create a workflow application. You must specify the updated workflow definition, and
    // you may provide an updated WorkflowIdentity if desired to reflect the update.
    WorkflowIdentity identity = new WorkflowIdentity
    {
        Name = "MortgageWorkflow v1.1",
        Version = new Version(1, 1, 0, 0)
    };

    // Load the persisted workflow instance using the updated workflow definition
    // and with an updated WorkflowIdentity. In this example the MortgageWorkflow class
    // contains the updated definition.
    WorkflowApplication wfApp = new WorkflowApplication(new MortgageWorkflow(), identity);

    // Apply the dynamic update on the loaded instance.
    wfApp.Load(instance, map);

    // Unload the updated instance.
    wfApp.Unload();
}

恢復已更新的工作流程實例

動態更新套用後,工作流程實例可以繼續。 請注意,新的更新定義必須使用 和 WorkflowIdentity

備註

如需使用 WorkflowApplicationWorkflowIdentity的詳細資訊,請參閱 使用 WorkflowIdentity 和 Versioning

在下列範例中,使用先前範例中的 MortgageWorkflow_v1.1.xaml 工作流程已編譯過,現在使用更新的工作流程定義來載入並繼續運行。

// Load the persisted workflow instance using the updated workflow definition
// and updated WorkflowIdentity.
WorkflowIdentity identity = new WorkflowIdentity
{
    Name = "MortgageWorkflow v1.1",
    Version = new Version(1, 1, 0, 0)
};

WorkflowApplication wfApp = new WorkflowApplication(new MortgageWorkflow(), identity);

// Configure persistence and desired workflow event handlers.
// (Omitted for brevity.)
ConfigureWorkflowApplication(wfApp);

// Load the persisted workflow instance.
wfApp.Load(InstanceId);

// Resume the workflow.
// wfApp.ResumeBookmark(...);