作法:並存裝載工作流程的多個版本
WorkflowIdentity
提供一種方法,讓工作流程應用程式開發人員能夠將名稱和版本與工作流程定義產生關聯性,並為這項資訊與持續性工作流程執行個體建立關聯性。 此身分識別資訊可由工作流程應用程式開發人員使用以啟用案例 (例如並存執行多個版本的工作流程定義),以及提供動態更新等其他功能的基礎。 教學課程中的此步驟示範如何使用 WorkflowIdentity
同時裝載工作流程的多個版本。
本主題內容
在教學課程的這個步驟中,會修改工作流程的 WriteLine
活動以提供其他資訊,並新增 WriteLine
活動。 我們會儲存原始工作流程組件的複本,並更新主應用程式,以便同時執行原始和更新的工作流程。
注意
依照本主題中的步驟進行之前,請執行應用程式、啟動每種型別的數個工作流程,然後針對每個工作流程進行一或兩次猜測。 這些持續性的工作流程會用於此步驟和後續的這個步驟中:如何:更新執行中工作流程實例的定義。
製作 NumberGuessWorkflowActivities 專案的複本
在 Visual Studio 2012 中開啟 WF45GettingStartedTutorial 方案 (如果未開啟)。
按下 CTRL+SHIFT+B 以建置方案。
關閉 WF45GettingStartedTutorial 方案。
開啟 [Windows 檔案總管],並巡覽至教學課程方案檔和專案資料夾所在的資料夾。
在與 NumberGuessWorkflowHost 和 NumberGuessWorkflowActivities 相同的資料夾中建立一個名為 PreviousVersions 的新資料夾。 此資料夾用來儲存組件,這些組件包含在後續教學課程步驟中使用的不同工作流程版本。
巡覽至 NumberGuessWorkflowActivities\bin\debug 資料夾 (或 bin\release,取決於您的專案設定)。 複製 NumberGuessWorkflowActivities.dll 並將其貼入 PreviousVersions 資料夾。
將 PreviousVersions 資料夾中的 NumberGuessWorkflowActivities.dll 重新命名為 NumberGuessWorkflowActivities_v1.dll。
注意
本主題中的步驟示範管理組件的方法,這些組件用於包含多個工作流程版本。 您也可以使用其他方法,例如強式命名組件以及在全域組件快取中登錄這些組件。
在與 NumberGuessWorkflowHost、NumberGuessWorkflowActivities 及新加入之 PreviousVersions 資料夾相同的資料夾中,建立一個名為 NumberGuessWorkflowActivities_du 的新資料夾,然後將 NumberGuessWorkflowActivities 資料夾中的所有檔案和子資料夾複製到新的 NumberGuessWorkflowActivities_du 資料夾中。 此活動初始版的專案備份複本會用於 [如何:更新執行中工作流程實例的定義] 中。
在 Visual Studio 2012 中重新開啟 WF45GettingStartedTutorial 方案。
更新工作流程
本節已更新工作流程定義。 已更新回應使用者猜測的兩個 WriteLine
活動,並新增可在猜測數字後提供遊戲其他相關資訊的 WriteLine
活動。
更新 StateMachine 工作流程
在 [方案總管] 中的 NumberGuessWorkflowActivities 專案下,按兩下 StateMachineNumberGuessWorkflow.xaml。
按兩下狀態機器上的 [猜測不正確] 轉換。
更新
Text
活動中最左邊WriteLine
的If
。Guess & " is too low."
Guess + " is too low."
更新
Text
活動中最右邊WriteLine
的If
。Guess & " is too high."
Guess + " is too high."
按一下工作流程設計工具最上方階層連接列中的 StateMachine,以回到工作流程設計工具中的整體狀態機器檢視。
按兩下狀態機器上的 [猜測正確] 轉換。
從 [工具箱] 的 [Primitives] 區段中,將 WriteLine 活動拖放到轉換的 [在此置放動作活動] 標籤上。
在
Text
屬性方塊中輸入下列運算式。Guess & " is correct. You guessed it in " & Turns & " turns."
Guess + " is correct. You guessed it in " + Turns + " turns."
更新 Flowchart 工作流程
在 [方案總管] 中的 NumberGuessWorkflowActivities 專案下,按兩下 FlowchartNumberGuessWorkflow.xaml。
更新最左邊
Text
活動的WriteLine
。Guess & " is too low."
Guess + " is too low."
更新最右邊
Text
活動的WriteLine
。Guess & " is too high."
Guess + " is too high."
從 [工具箱] 的 [Primitives] 區段中,將 WriteLine 活動拖放到最上面
FlowDecision
的True
動作的置放點上。WriteLine
活動會加入到流程圖中,並連結至True
動作的FlowDecision
。在
Text
屬性方塊中輸入下列運算式。Guess & " is correct. You guessed it in " & Turns & " turns."
Guess + " is correct. You guessed it in " + Turns + " turns."
更新 Sequential 工作流程
在 [方案總管] 中的 NumberGuessWorkflowActivities 專案下,按兩下 SequentialNumberGuessWorkflow.xaml。
更新
Text
活動中最左邊WriteLine
的If
。Guess & " is too low."
Guess + " is too low."
更新
Text
活動中最右邊WriteLine
活動的If
。Guess & " is too high."
Guess + " is too high."
從 [工具箱] 的 [Primitives] 區段中拖曳 WriteLine 活動,並將其放在 DoWhile 活動之後,以便 WriteLine 成為根
Sequence
活動中的最後一個活動。在
Text
屬性方塊中輸入下列運算式。Guess & " is correct. You guessed it in " & Turns & " turns."
Guess + " is correct. You guessed it in " + Turns + " turns."
更新 WorkflowVersionMap 以包含舊版的工作流程
按兩下 NumberGuessWorkflowHost 專案底下的 WorkflowVersionMap.cs (或 WorkflowVersionMap.vb) 加以開啟。
將下列
using
(或Imports
) 陳述式加入至檔案最上方的其他using
(或Imports
) 陳述式。Imports System.Reflection Imports System.IO
using System.Reflection; using System.IO;
將三個新的工作流程識別加入到三個現有工作流程識別宣告的正下方。 這些新的
v1
工作流程識別將用來針對在更新前啟動之工作流程,提供正確的工作流程定義。'Current version identities. Public StateMachineNumberGuessIdentity As WorkflowIdentity Public FlowchartNumberGuessIdentity As WorkflowIdentity Public SequentialNumberGuessIdentity As WorkflowIdentity 'v1 Identities. Public StateMachineNumberGuessIdentity_v1 As WorkflowIdentity Public FlowchartNumberGuessIdentity_v1 As WorkflowIdentity Public SequentialNumberGuessIdentity_v1 As WorkflowIdentity
// Current version identities. static public WorkflowIdentity StateMachineNumberGuessIdentity; static public WorkflowIdentity FlowchartNumberGuessIdentity; static public WorkflowIdentity SequentialNumberGuessIdentity; // v1 identities. static public WorkflowIdentity StateMachineNumberGuessIdentity_v1; static public WorkflowIdentity FlowchartNumberGuessIdentity_v1; static public WorkflowIdentity SequentialNumberGuessIdentity_v1;
在
WorkflowVersionMap
建構函式中,將三個目前工作流程識別的Version
屬性更新為2.0.0.0
。'Add the current workflow version identities. StateMachineNumberGuessIdentity = New WorkflowIdentity With { .Name = "StateMachineNumberGuessWorkflow", .Version = New Version(2, 0, 0, 0) } FlowchartNumberGuessIdentity = New WorkflowIdentity With { .Name = "FlowchartNumberGuessWorkflow", .Version = New Version(2, 0, 0, 0) } SequentialNumberGuessIdentity = New WorkflowIdentity With { .Name = "SequentialNumberGuessWorkflow", .Version = New Version(2, 0, 0, 0) } map.Add(StateMachineNumberGuessIdentity, New StateMachineNumberGuessWorkflow()) map.Add(FlowchartNumberGuessIdentity, New FlowchartNumberGuessWorkflow()) map.Add(SequentialNumberGuessIdentity, New SequentialNumberGuessWorkflow())
// Add the current workflow version identities. StateMachineNumberGuessIdentity = new WorkflowIdentity { Name = "StateMachineNumberGuessWorkflow", // Version = new Version(1, 0, 0, 0), Version = new Version(2, 0, 0, 0) }; FlowchartNumberGuessIdentity = new WorkflowIdentity { Name = "FlowchartNumberGuessWorkflow", // Version = new Version(1, 0, 0, 0), Version = new Version(2, 0, 0, 0) }; SequentialNumberGuessIdentity = new WorkflowIdentity { Name = "SequentialNumberGuessWorkflow", // Version = new Version(1, 0, 0, 0), Version = new Version(2, 0, 0, 0) }; map.Add(StateMachineNumberGuessIdentity, new StateMachineNumberGuessWorkflow()); map.Add(FlowchartNumberGuessIdentity, new FlowchartNumberGuessWorkflow()); map.Add(SequentialNumberGuessIdentity, new SequentialNumberGuessWorkflow());
將目前工作流程版本加入到字典中的程式碼會使用專案中參考的目前版本,因此您不需要更新初始化工作流程定義的程式碼。
將下列程式碼加入到建構函式中,放在將目前版本加入到字典中的程式碼之後。
'Initialize the previous workflow version identities. StateMachineNumberGuessIdentity_v1 = New WorkflowIdentity With { .Name = "StateMachineNumberGuessWorkflow", .Version = New Version(1, 0, 0, 0) } FlowchartNumberGuessIdentity_v1 = New WorkflowIdentity With { .Name = "FlowchartNumberGuessWorkflow", .Version = New Version(1, 0, 0, 0) } SequentialNumberGuessIdentity_v1 = New WorkflowIdentity With { .Name = "SequentialNumberGuessWorkflow", .Version = New Version(1, 0, 0, 0) }
// Initialize the previous workflow version identities. StateMachineNumberGuessIdentity_v1 = new WorkflowIdentity { Name = "StateMachineNumberGuessWorkflow", Version = new Version(1, 0, 0, 0) }; FlowchartNumberGuessIdentity_v1 = new WorkflowIdentity { Name = "FlowchartNumberGuessWorkflow", Version = new Version(1, 0, 0, 0) }; SequentialNumberGuessIdentity_v1 = new WorkflowIdentity { Name = "SequentialNumberGuessWorkflow", Version = new Version(1, 0, 0, 0) };
這些工作流程識別都與對應工作流程定義的初始版本相關聯。
接下來,載入包含工作流程定義初始版本的組件,建立對應的工作流程定義並將其加入到字典中。
'Add the previous version workflow identities to the dictionary along with 'the corresponding workflow definitions loaded from the v1 assembly. 'Assembly.LoadFile requires an absolute path so convert this relative path 'to an absolute path. Dim v1AssemblyPath As String = "..\..\..\PreviousVersions\NumberGuessWorkflowActivities_v1.dll" v1AssemblyPath = Path.GetFullPath(v1AssemblyPath) Dim v1Assembly As Assembly = Assembly.LoadFile(v1AssemblyPath) map.Add(StateMachineNumberGuessIdentity_v1, v1Assembly.CreateInstance("NumberGuessWorkflowActivities.StateMachineNumberGuessWorkflow")) map.Add(SequentialNumberGuessIdentity_v1, v1Assembly.CreateInstance("NumberGuessWorkflowActivities.SequentialNumberGuessWorkflow")) map.Add(FlowchartNumberGuessIdentity_v1, v1Assembly.CreateInstance("NumberGuessWorkflowActivities.FlowchartNumberGuessWorkflow"))
// Add the previous version workflow identities to the dictionary along with // the corresponding workflow definitions loaded from the v1 assembly. // Assembly.LoadFile requires an absolute path so convert this relative path // to an absolute path. string v1AssemblyPath = @"..\..\..\PreviousVersions\NumberGuessWorkflowActivities_v1.dll"; v1AssemblyPath = Path.GetFullPath(v1AssemblyPath); Assembly v1Assembly = Assembly.LoadFile(v1AssemblyPath); map.Add(StateMachineNumberGuessIdentity_v1, v1Assembly.CreateInstance("NumberGuessWorkflowActivities.StateMachineNumberGuessWorkflow") as Activity); map.Add(SequentialNumberGuessIdentity_v1, v1Assembly.CreateInstance("NumberGuessWorkflowActivities.SequentialNumberGuessWorkflow") as Activity); map.Add(FlowchartNumberGuessIdentity_v1, v1Assembly.CreateInstance("NumberGuessWorkflowActivities.FlowchartNumberGuessWorkflow") as Activity);
以下範例是更新之
WorkflowVersionMap
類別的完整清單。Public Module WorkflowVersionMap Dim map As Dictionary(Of WorkflowIdentity, Activity) 'Current version identities. Public StateMachineNumberGuessIdentity As WorkflowIdentity Public FlowchartNumberGuessIdentity As WorkflowIdentity Public SequentialNumberGuessIdentity As WorkflowIdentity 'v1 Identities. Public StateMachineNumberGuessIdentity_v1 As WorkflowIdentity Public FlowchartNumberGuessIdentity_v1 As WorkflowIdentity Public SequentialNumberGuessIdentity_v1 As WorkflowIdentity Sub New() map = New Dictionary(Of WorkflowIdentity, Activity) 'Add the current workflow version identities. StateMachineNumberGuessIdentity = New WorkflowIdentity With { .Name = "StateMachineNumberGuessWorkflow", .Version = New Version(2, 0, 0, 0) } FlowchartNumberGuessIdentity = New WorkflowIdentity With { .Name = "FlowchartNumberGuessWorkflow", .Version = New Version(2, 0, 0, 0) } SequentialNumberGuessIdentity = New WorkflowIdentity With { .Name = "SequentialNumberGuessWorkflow", .Version = New Version(2, 0, 0, 0) } map.Add(StateMachineNumberGuessIdentity, New StateMachineNumberGuessWorkflow()) map.Add(FlowchartNumberGuessIdentity, New FlowchartNumberGuessWorkflow()) map.Add(SequentialNumberGuessIdentity, New SequentialNumberGuessWorkflow()) 'Initialize the previous workflow version identities. StateMachineNumberGuessIdentity_v1 = New WorkflowIdentity With { .Name = "StateMachineNumberGuessWorkflow", .Version = New Version(1, 0, 0, 0) } FlowchartNumberGuessIdentity_v1 = New WorkflowIdentity With { .Name = "FlowchartNumberGuessWorkflow", .Version = New Version(1, 0, 0, 0) } SequentialNumberGuessIdentity_v1 = New WorkflowIdentity With { .Name = "SequentialNumberGuessWorkflow", .Version = New Version(1, 0, 0, 0) } 'Add the previous version workflow identities to the dictionary along with 'the corresponding workflow definitions loaded from the v1 assembly. 'Assembly.LoadFile requires an absolute path so convert this relative path 'to an absolute path. Dim v1AssemblyPath As String = "..\..\..\PreviousVersions\NumberGuessWorkflowActivities_v1.dll" v1AssemblyPath = Path.GetFullPath(v1AssemblyPath) Dim v1Assembly As Assembly = Assembly.LoadFile(v1AssemblyPath) map.Add(StateMachineNumberGuessIdentity_v1, v1Assembly.CreateInstance("NumberGuessWorkflowActivities.StateMachineNumberGuessWorkflow")) map.Add(SequentialNumberGuessIdentity_v1, v1Assembly.CreateInstance("NumberGuessWorkflowActivities.SequentialNumberGuessWorkflow")) map.Add(FlowchartNumberGuessIdentity_v1, v1Assembly.CreateInstance("NumberGuessWorkflowActivities.FlowchartNumberGuessWorkflow")) End Sub Public Function GetWorkflowDefinition(identity As WorkflowIdentity) As Activity Return map(identity) End Function Public Function GetIdentityDescription(identity As WorkflowIdentity) As String Return identity.ToString() End Function End Module
public static class WorkflowVersionMap { static Dictionary<WorkflowIdentity, Activity> map; // Current version identities. static public WorkflowIdentity StateMachineNumberGuessIdentity; static public WorkflowIdentity FlowchartNumberGuessIdentity; static public WorkflowIdentity SequentialNumberGuessIdentity; // v1 identities. static public WorkflowIdentity StateMachineNumberGuessIdentity_v1; static public WorkflowIdentity FlowchartNumberGuessIdentity_v1; static public WorkflowIdentity SequentialNumberGuessIdentity_v1; static WorkflowVersionMap() { map = new Dictionary<WorkflowIdentity, Activity>(); // Add the current workflow version identities. StateMachineNumberGuessIdentity = new WorkflowIdentity { Name = "StateMachineNumberGuessWorkflow", // Version = new Version(1, 0, 0, 0), Version = new Version(2, 0, 0, 0) }; FlowchartNumberGuessIdentity = new WorkflowIdentity { Name = "FlowchartNumberGuessWorkflow", // Version = new Version(1, 0, 0, 0), Version = new Version(2, 0, 0, 0) }; SequentialNumberGuessIdentity = new WorkflowIdentity { Name = "SequentialNumberGuessWorkflow", // Version = new Version(1, 0, 0, 0), Version = new Version(2, 0, 0, 0) }; map.Add(StateMachineNumberGuessIdentity, new StateMachineNumberGuessWorkflow()); map.Add(FlowchartNumberGuessIdentity, new FlowchartNumberGuessWorkflow()); map.Add(SequentialNumberGuessIdentity, new SequentialNumberGuessWorkflow()); // Initialize the previous workflow version identities. StateMachineNumberGuessIdentity_v1 = new WorkflowIdentity { Name = "StateMachineNumberGuessWorkflow", Version = new Version(1, 0, 0, 0) }; FlowchartNumberGuessIdentity_v1 = new WorkflowIdentity { Name = "FlowchartNumberGuessWorkflow", Version = new Version(1, 0, 0, 0) }; SequentialNumberGuessIdentity_v1 = new WorkflowIdentity { Name = "SequentialNumberGuessWorkflow", Version = new Version(1, 0, 0, 0) }; // Add the previous version workflow identities to the dictionary along with // the corresponding workflow definitions loaded from the v1 assembly. // Assembly.LoadFile requires an absolute path so convert this relative path // to an absolute path. string v1AssemblyPath = @"..\..\..\PreviousVersions\NumberGuessWorkflowActivities_v1.dll"; v1AssemblyPath = Path.GetFullPath(v1AssemblyPath); Assembly v1Assembly = Assembly.LoadFile(v1AssemblyPath); map.Add(StateMachineNumberGuessIdentity_v1, v1Assembly.CreateInstance("NumberGuessWorkflowActivities.StateMachineNumberGuessWorkflow") as Activity); map.Add(SequentialNumberGuessIdentity_v1, v1Assembly.CreateInstance("NumberGuessWorkflowActivities.SequentialNumberGuessWorkflow") as Activity); map.Add(FlowchartNumberGuessIdentity_v1, v1Assembly.CreateInstance("NumberGuessWorkflowActivities.FlowchartNumberGuessWorkflow") as Activity); } public static Activity GetWorkflowDefinition(WorkflowIdentity identity) { return map[identity]; } public static string GetIdentityDescription(WorkflowIdentity identity) { return identity.ToString(); } }
若要建置並執行應用程式
按下 CTRL+SHIFT+B 建置應用程式,然後按下 CTRL+F5 啟動。
按一下 [New Game] 來啟動新的工作流程。 工作流程的版本會顯示在狀態視窗下,反映從相關聯的
WorkflowIdentity
更新的版本。 記下InstanceId
,當工作流程完成時,您就可以檢視該工作流程的追蹤檔案,然後輸入猜測直到遊戲完成為止。 請注意,狀態視窗中所顯示的使用者猜測資訊,會以WriteLine
活動的更新為根據。Please enter a number between 1 and 10 5 is too high. Please enter a number between 1 and 10 3 is too high. Please enter a number between 1 and 10 1 is too low. Please enter a number between 1 and 10 Congratulations, you guessed the number in 4 turns.
注意
即會顯示從
WriteLine
活動更新的文字,但不會顯示本主題中最後加入的WriteLine
活動的輸出。 這是因為狀態視窗是由PersistableIdle
處理常式更新的。 由於工作流程已完成且不會在最後一個活動之後閒置,因此不會呼叫PersistableIdle
處理常式。 但是,Completed
處理常式會在狀態視窗顯示類似的訊息。 如果需要,可以將程式碼加入到Completed
處理常式,從StringWriter
擷取文字並將其顯示在狀態視窗中。開啟 [Windows 檔案總管] 並巡覽至 NumberGuessWorkflowHost\bin\debug 資料夾 (或 bin\release,取決於您的專案設定),然後使用記事本開啟已完成工作流程對應的追蹤檔案。 如果您沒有記下
InstanceId
,可以使用 Windows 檔案總管中的 [修改日期] 資訊來找到正確的追蹤檔案。Please enter a number between 1 and 10 5 is too high. Please enter a number between 1 and 10 3 is too high. Please enter a number between 1 and 10 1 is too low. Please enter a number between 1 and 10 2 is correct. You guessed it in 4 turns.
追蹤檔中包含更新的
WriteLine
輸出,包括在本主題中加入之WriteLine
的輸出。切換回猜數字應用程式,並選取其中一個在更新之前啟動的工作流程。 您可以查看顯示在狀態視窗下方的版本資訊,找出目前選取之工作流程的版本。 輸入一些猜測,請注意,狀態更新會比對
WriteLine
活動輸出與舊版的輸出,而且不包含使用者的猜測。 這是因為這些工作流程使用的舊版工作流程定義不含WriteLine
更新。在下一個步驟 (如何:更新執行中工作流程實例的定義) 中,會更新執行中的
v1
工作流程實例,使其包含新功能作為v2
實例。