Procedura: aggiornare la definizione di un'istanza del flusso di lavoro in esecuzione
L'aggiornamento dinamico fornisce agli sviluppatori di applicazioni del flusso di lavoro un meccanismo per aggiornare la definizione del flusso di lavoro di un'istanza persistente del flusso di lavoro. La modifica richiesta può servire a implementare la correzione di un bug, nuovi requisiti o modifiche impreviste. In questo passaggio dell'esercitazione viene illustrato come usare l'aggiornamento dinamico al fine di modificare le istanze persistenti del flusso di lavoro per determinare il numero v1
in base alla nuova funzionalità introdotta in Procedura: Ospitare più versioni di un flusso di lavoro side-by-side.
Per creare il progetto CreateUpdateMaps
Fare clic con il pulsante destro del mouse su WF45GettingStartedTutorial in Esplora soluzioni e scegliere Aggiungi, Nuovo progetto.
Nel nodo Installato selezionare Visual C#, Windows (o Visual Basic, Windows).
Nota
A seconda del linguaggio di programmazione configurato come linguaggio principale in Visual Studio, sotto il nodo Altri linguaggi del nodo Installato viene visualizzato il nodo Visual C# o Visual Basic .
Assicurarsi che nell'elenco a discesa della versione di .NET Framework sia selezionata l'opzione .NET Framework 4.5 . Selezionare Applicazione console dall'elenco Windows. Digitare CreateUpdateMaps nella casella Nome, quindi scegliere OK.
Fare clic con il pulsante destro del mouse su CreateUpdateMaps in Esplora soluzioni e scegliere Aggiungi riferimento.
Selezionare Framework dal nodo Assembly nell'elenco Aggiungi riferimento. Digitare System.Activities nella casella Cerca assembly per filtrare gli assembly e rendere più semplice la selezione dei riferimenti desiderati.
Selezionare la casella di controllo accanto a System.Activities nell'elenco Risultati ricerca.
Digitare Serializzazione nella casella Cerca assembly e selezionare la casella di controllo accanto a System.Runtime.Serialization nell'elenco Risultati ricerca.
Digitare System.Xaml nella casella Cerca assembly e selezionare la casella di controllo accanto a System.Xaml nell'elenco Risultati ricerca.
Fare clic su OK per chiudere Gestione riferimenti e aggiungere i riferimenti.
Aggiungere le seguenti istruzioni
using
(oImports
) nella parte superiore del file con le altre istruzioniusing
(oImports
).Imports System.Activities Imports System.Activities.Statements Imports System.Xaml Imports System.Reflection Imports System.IO Imports System.Activities.XamlIntegration Imports System.Activities.DynamicUpdate Imports System.Runtime.Serialization Imports Microsoft.VisualBasic.Activities
using System.Activities; using System.Activities.Statements; using System.IO; using System.Xaml; using System.Reflection; using System.Activities.XamlIntegration; using System.Activities.DynamicUpdate; using System.Runtime.Serialization; using Microsoft.CSharp.Activities;
Aggiungere i due membri stringa seguenti alla classe
Program
(oModule1
).Const mapPath = "..\..\..\PreviousVersions" Const definitionPath = "..\..\..\NumberGuessWorkflowActivities_du"
const string mapPath = @"..\..\..\PreviousVersions"; const string definitionPath = @"..\..\..\NumberGuessWorkflowActivities_du";
Aggiungere il seguente metodo
StartUpdate
alla classeProgram
(oModule1
). Tramite questo metodo viene caricata la definizione del flusso di lavoro XAML specificata in un oggettoActivityBuilder
, quindi viene chiamatoDynamicUpdate.PrepareForUpdate
. TramitePrepareForUpdate
viene creata una copia della definizione del flusso di lavoro nell'oggettoActivityBuilder
. Al termine della modifica della definizione del flusso di lavoro, questa copia viene usata insieme alla definizione in questione modificata per creare il mapping di aggiornamento.Private Function StartUpdate(name As String) As ActivityBuilder 'Create the XamlXmlReaderSettings. Dim readerSettings As XamlReaderSettings = New XamlXmlReaderSettings() 'In the XAML the "local" namespace refers to artifacts that come from 'the same project as the XAML. When loading XAML if the currently executing 'assembly is not the same assembly that was referred to as "local" in the XAML 'LocalAssembly must be set to the assembly containing the artifacts. 'Assembly.LoadFile requires an absolute path so convert this relative path 'to an absolute path. readerSettings.LocalAssembly = Assembly.LoadFile( Path.GetFullPath(Path.Combine(mapPath, "NumberGuessWorkflowActivities_v1.dll"))) Dim fullPath As String = Path.Combine(definitionPath, name) Dim xamlReader As XamlXmlReader = New XamlXmlReader(fullPath, readerSettings) 'Load the workflow definition into an ActivityBuilder. Dim wf As ActivityBuilder = XamlServices.Load( ActivityXamlServices.CreateBuilderReader(xamlReader)) 'PrepareForUpdate makes a copy of the workflow definition in the 'ActivityBuilder that is used for comparison when the update 'map is created. DynamicUpdateServices.PrepareForUpdate(wf) Return wf End Function
private static ActivityBuilder StartUpdate(string name) { // Create the XamlXmlReaderSettings. XamlXmlReaderSettings readerSettings = new XamlXmlReaderSettings() { // In the XAML the "local" namespace refers to artifacts that come from // the same project as the XAML. When loading XAML if the currently executing // assembly is not the same assembly that was referred to as "local" in the XAML // LocalAssembly must be set to the assembly containing the artifacts. // Assembly.LoadFile requires an absolute path so convert this relative path // to an absolute path. LocalAssembly = Assembly.LoadFile( Path.GetFullPath(Path.Combine(mapPath, "NumberGuessWorkflowActivities_v1.dll"))) }; string path = Path.Combine(definitionPath, name); XamlXmlReader xamlReader = new XamlXmlReader(path, readerSettings); // Load the workflow definition into an ActivityBuilder. ActivityBuilder wf = XamlServices.Load( ActivityXamlServices.CreateBuilderReader(xamlReader)) as ActivityBuilder; // PrepareForUpdate makes a copy of the workflow definition in the // ActivityBuilder that is used for comparison when the update // map is created. DynamicUpdateServices.PrepareForUpdate(wf); return wf; }
Successivamente, aggiungere l'oggetto
CreateUpdateMethod
seguente alla classeProgram
(oModule1
). In questo modo viene creato un mapping di aggiornamento dinamico tramite la chiamata a DynamicUpdateServices.CreateUpdateMap, quindi viene salvato il mapping di aggiornamento usando il nome specificato. In questo mapping di aggiornamento sono contenute le informazioni richieste dal runtime del flusso di lavoro per aggiornare un'istanza persistente del flusso di lavoro che è stata avviata usando la definizione originale del flusso di lavoro contenuta nell'oggettoActivityBuilder
in modo che venga completata usando la definizione aggiornata del flusso di lavoro.Private Sub CreateUpdateMaps(wf As ActivityBuilder, name As String) 'Create the UpdateMap. Dim map As DynamicUpdateMap = DynamicUpdateServices.CreateUpdateMap(wf) 'Serialize it to a file. Dim mapFullPath As String = Path.Combine(mapPath, name) Dim sz As DataContractSerializer = New DataContractSerializer(GetType(DynamicUpdateMap)) Using fs As FileStream = File.Open(mapFullPath, FileMode.Create) sz.WriteObject(fs, map) End Using End Sub
private static void CreateUpdateMaps(ActivityBuilder wf, string name) { // Create the UpdateMap. DynamicUpdateMap map = DynamicUpdateServices.CreateUpdateMap(wf); // Serialize it to a file. string path = Path.Combine(mapPath, name); DataContractSerializer sz = new DataContractSerializer(typeof(DynamicUpdateMap)); using (FileStream fs = System.IO.File.Open(path, FileMode.Create)) { sz.WriteObject(fs, map); } }
Aggiungere il seguente metodo
SaveUpdatedDefinition
alla classeProgram
(oModule1
). Tramite questo metodo la definizione aggiornata del flusso di lavoro viene salvata una volta creato il mapping di aggiornamento.Private Sub SaveUpdatedDefinition(wf As ActivityBuilder, name As String) Dim xamlPath As String = Path.Combine(definitionPath, name) Dim sw As StreamWriter = File.CreateText(xamlPath) Dim xw As XamlWriter = ActivityXamlServices.CreateBuilderWriter( New XamlXmlWriter(sw, New XamlSchemaContext())) XamlServices.Save(xw, wf) sw.Close() End Sub
private static void SaveUpdatedDefinition(ActivityBuilder wf, string name) { string xamlPath = Path.Combine(definitionPath, name); StreamWriter sw = File.CreateText(xamlPath); XamlWriter xw = ActivityXamlServices.CreateBuilderWriter( new XamlXmlWriter(sw, new XamlSchemaContext())); XamlServices.Save(xw, wf); sw.Close(); }
Per aggiornare StateMachineNumberGuessWorkflow
Aggiungere un oggetto
CreateStateMachineUpdateMap
alla classeProgram
(oModule1
).Private Sub CreateStateMachineUpdateMap() End Sub
private static void CreateStateMachineUpdateMap() { }
Effettuare una chiamata a
StartUpdate
, quindi ottenere un riferimento all'attivitàStateMachine
radice del flusso di lavoro.Dim wf As ActivityBuilder = StartUpdate("StateMachineNumberGuessWorkflow.xaml") 'Get a reference to the root StateMachine activity. Dim sm As StateMachine = wf.Implementation
ActivityBuilder wf = StartUpdate("StateMachineNumberGuessWorkflow.xaml"); // Get a reference to the root StateMachine activity. StateMachine sm = wf.Implementation as StateMachine;
Successivamente, aggiornare le espressioni delle due attività
WriteLine
tramite le quali viene visualizzato se l’ipotesi dell'utente è troppo alta o troppo bassa, in modo da corrispondere agli aggiornamenti effettuati in Procedura: Ospitare più versioni di un flusso di lavoro side-by-Side.'Update the Text of the two WriteLine activities that write the 'results of the user's guess. They are contained in the workflow as the 'Then and Else action of the If activity in sm.States[1].Transitions[1].Action. Dim guessLow As Statements.If = sm.States(1).Transitions(1).Action 'Update the "too low" message. Dim tooLow As WriteLine = guessLow.Then tooLow.Text = New VisualBasicValue(Of String)("Guess.ToString() & "" is too low.""") 'Update the "too high" message. Dim tooHigh As WriteLine = guessLow.Else tooHigh.Text = New VisualBasicValue(Of String)("Guess.ToString() & "" is too high.""")
// Update the Text of the two WriteLine activities that write the // results of the user's guess. They are contained in the workflow as the // Then and Else action of the If activity in sm.States[1].Transitions[1].Action. If guessLow = sm.States[1].Transitions[1].Action as If; // Update the "too low" message. WriteLine tooLow = guessLow.Then as WriteLine; tooLow.Text = new CSharpValue<string>("Guess.ToString() + \" is too low.\""); // Update the "too high" message. WriteLine tooHigh = guessLow.Else as WriteLine; tooHigh.Text = new CSharpValue<string>("Guess.ToString() + \" is too high.\"");
Successivamente, aggiungere una nuova attività
WriteLine
tramite cui viene visualizzato il messaggio di chiusura.'Create the new WriteLine that displays the closing message. Dim wl As New WriteLine() With { .Text = New VisualBasicValue(Of String) _ ("Guess.ToString() + "" is correct. You guessed it in "" & Turns.ToString() & "" turns.""") } 'Add it as the Action for the Guess Correct transition. The Guess Correct 'transition is the first transition of States[1]. The transitions are listed 'at the bottom of the State activity designer. sm.States(1).Transitions(0).Action = wl
// Create the new WriteLine that displays the closing message. WriteLine wl = new WriteLine { Text = new CSharpValue<string>("Guess.ToString() + \" is correct. You guessed it in \" + Turns.ToString() + \" turns.\"") }; // Add it as the Action for the Guess Correct transition. The Guess Correct // transition is the first transition of States[1]. The transitions are listed // at the bottom of the State activity designer. sm.States[1].Transitions[0].Action = wl;
Dopo aver aggiornato il flusso di lavoro, chiamare
CreateUpdateMaps
eSaveUpdatedDefinition
. TramiteCreateUpdateMaps
viene creato e salvato l'oggettoDynamicUpdateMap
, mentre tramiteSaveUpdatedDefinition
viene salvata la definizione aggiornata del flusso di lavoro.'Create the update map. CreateUpdateMaps(wf, "StateMachineNumberGuessWorkflow.map") 'Save the updated workflow definition. SaveUpdatedDefinition(wf, "StateMachineNumberGuessWorkflow_du.xaml")
// Create the update map. CreateUpdateMaps(wf, "StateMachineNumberGuessWorkflow.map"); // Save the updated workflow definition. SaveUpdatedDefinition(wf, "StateMachineNumberGuessWorkflow_du.xaml");
Nell'esempio seguente viene mostrato il metodo
CreateStateMachineUpdateMap
completato.Private Sub CreateStateMachineUpdateMap() Dim wf As ActivityBuilder = StartUpdate("StateMachineNumberGuessWorkflow.xaml") 'Get a reference to the root StateMachine activity. Dim sm As StateMachine = wf.Implementation 'Update the Text of the two WriteLine activities that write the 'results of the user's guess. They are contained in the workflow as the 'Then and Else action of the If activity in sm.States[1].Transitions[1].Action. Dim guessLow As Statements.If = sm.States(1).Transitions(1).Action 'Update the "too low" message. Dim tooLow As WriteLine = guessLow.Then tooLow.Text = New VisualBasicValue(Of String)("Guess.ToString() & "" is too low.""") 'Update the "too high" message. Dim tooHigh As WriteLine = guessLow.Else tooHigh.Text = New VisualBasicValue(Of String)("Guess.ToString() & "" is too high.""") 'Create the new WriteLine that displays the closing message. Dim wl As New WriteLine() With { .Text = New VisualBasicValue(Of String) _ ("Guess.ToString() + "" is correct. You guessed it in "" & Turns.ToString() & "" turns.""") } 'Add it as the Action for the Guess Correct transition. The Guess Correct 'transition is the first transition of States[1]. The transitions are listed 'at the bottom of the State activity designer. sm.States(1).Transitions(0).Action = wl 'Create the update map. CreateUpdateMaps(wf, "StateMachineNumberGuessWorkflow.map") 'Save the updated workflow definition. SaveUpdatedDefinition(wf, "StateMachineNumberGuessWorkflow_du.xaml") End Sub
private static void CreateStateMachineUpdateMap() { ActivityBuilder wf = StartUpdate("StateMachineNumberGuessWorkflow.xaml"); // Get a reference to the root StateMachine activity. StateMachine sm = wf.Implementation as StateMachine; // Update the Text of the two WriteLine activities that write the // results of the user's guess. They are contained in the workflow as the // Then and Else action of the If activity in sm.States[1].Transitions[1].Action. If guessLow = sm.States[1].Transitions[1].Action as If; // Update the "too low" message. WriteLine tooLow = guessLow.Then as WriteLine; tooLow.Text = new CSharpValue<string>("Guess.ToString() + \" is too low.\""); // Update the "too high" message. WriteLine tooHigh = guessLow.Else as WriteLine; tooHigh.Text = new CSharpValue<string>("Guess.ToString() + \" is too high.\""); // Create the new WriteLine that displays the closing message. WriteLine wl = new WriteLine { Text = new CSharpValue<string>("Guess.ToString() + \" is correct. You guessed it in \" + Turns.ToString() + \" turns.\"") }; // Add it as the Action for the Guess Correct transition. The Guess Correct // transition is the first transition of States[1]. The transitions are listed // at the bottom of the State activity designer. sm.States[1].Transitions[0].Action = wl; // Create the update map. CreateUpdateMaps(wf, "StateMachineNumberGuessWorkflow.map"); // Save the updated workflow definition. SaveUpdatedDefinition(wf, "StateMachineNumberGuessWorkflow_du.xaml"); }
Per aggiornare FlowchartNumberGuessWorkflow
Aggiungere l'oggetto
CreateFlowchartUpdateMethod
seguente alla classeProgram
(oModule1
). Questo metodo è simile aCreateStateMachineUpdateMap
. Inizia con una chiamata all'oggettoStartUpdate
, consente di aggiornare la definizione del flusso di lavoro del diagramma di flusso, quindi termina salvando il mapping di aggiornamento e la definizione aggiornata del flusso di lavoro.Private Sub CreateFlowchartUpdateMap() Dim wf As ActivityBuilder = StartUpdate("FlowchartNumberGuessWorkflow.xaml") 'Get a reference to the root Flowchart activity. Dim fc As Flowchart = wf.Implementation 'Update the Text of the two WriteLine activities that write the 'results of the user's guess. They are contained in the workflow as the 'True and False action of the "Guess < Target" FlowDecision, which is 'Nodes[4]. Dim guessLow As FlowDecision = fc.Nodes(4) 'Update the "too low" message. Dim trueStep As FlowStep = guessLow.True Dim tooLow As WriteLine = trueStep.Action tooLow.Text = New VisualBasicValue(Of String)("Guess.ToString() & "" is too low.""") 'Update the "too high" message. Dim falseStep As FlowStep = guessLow.False Dim tooHigh As WriteLine = falseStep.Action tooHigh.Text = New VisualBasicValue(Of String)("Guess.ToString() & "" is too high.""") 'Create the new WriteLine that displays the closing message. Dim wl As New WriteLine() With { .Text = New VisualBasicValue(Of String) _ ("Guess.ToString() + "" is correct. You guessed it in "" & Turns.ToString() & "" turns.""") } 'Create a FlowStep to hold the WriteLine. Dim closingStep As New FlowStep() With { .Action = wl } 'Add this new FlowStep to the True action of the '"Guess = Guess" FlowDecision Dim guessCorrect As FlowDecision = fc.Nodes(3) guessCorrect.True = closingStep 'Add the new FlowStep to the Nodes collection. 'If closingStep was replacing an existing node then 'we would need to remove that Step from the collection. 'In this example there was no existing True step to remove. fc.Nodes.Add(closingStep) 'Create the update map. CreateUpdateMaps(wf, "FlowchartNumberGuessWorkflow.map") 'Save the updated workflow definition. SaveUpdatedDefinition(wf, "FlowchartNumberGuessWorkflow_du.xaml") End Sub
private static void CreateFlowchartUpdateMap() { ActivityBuilder wf = StartUpdate("FlowchartNumberGuessWorkflow.xaml"); // Get a reference to the root Flowchart activity. Flowchart fc = wf.Implementation as Flowchart; // Update the Text of the two WriteLine activities that write the // results of the user's guess. They are contained in the workflow as the // True and False action of the "Guess < Target" FlowDecision, which is // Nodes[4]. FlowDecision guessLow = fc.Nodes[4] as FlowDecision; // Update the "too low" message. FlowStep trueStep = guessLow.True as FlowStep; WriteLine tooLow = trueStep.Action as WriteLine; tooLow.Text = new CSharpValue<string>("Guess.ToString() + \" is too low.\""); // Update the "too high" message. FlowStep falseStep = guessLow.False as FlowStep; WriteLine tooHigh = falseStep.Action as WriteLine; tooHigh.Text = new CSharpValue<string>("Guess.ToString() + \" is too high.\""); // Add the new WriteLine that displays the closing message. WriteLine wl = new WriteLine { Text = new CSharpValue<string>("Guess.ToString() + \" is correct. You guessed it in \" + Turns.ToString() + \" turns.\"") }; // Create a FlowStep to hold the WriteLine. FlowStep closingStep = new FlowStep { Action = wl }; // Add this new FlowStep to the True action of the // "Guess == Guess" FlowDecision FlowDecision guessCorrect = fc.Nodes[3] as FlowDecision; guessCorrect.True = closingStep; // Add the new FlowStep to the Nodes collection. // If closingStep was replacing an existing node then // we would need to remove that Step from the collection. // In this example there was no existing True step to remove. fc.Nodes.Add(closingStep); // Create the update map. CreateUpdateMaps(wf, "FlowchartNumberGuessWorkflow.map"); // Save the updated workflow definition. SaveUpdatedDefinition(wf, "FlowchartNumberGuessWorkflow_du.xaml"); }
Per aggiornare SequentialNumberGuessWorkflow
Aggiungere l'oggetto
CreateSequentialUpdateMethod
seguente alla classeProgram
(oModule1
). Questo metodo è simile ad altri due metodi. Inizia con una chiamata all'oggettoStartUpdate
, consente di aggiornare la definizione del flusso di lavoro sequenziale, quindi termina salvando il mapping di aggiornamento e la definizione aggiornata del flusso di lavoro.Private Sub CreateSequentialUpdateMap() Dim wf As ActivityBuilder = StartUpdate("SequentialNumberGuessWorkflow.xaml") 'Get a reference to the root activity in the workflow. Dim rootSequence As Sequence = wf.Implementation 'Update the Text of the two WriteLine activities that write the 'results of the user's guess. They are contained in the workflow as the 'Then and Else action of the "Guess < Target" If activity. 'Sequence[1]->DoWhile->Body->Sequence[2]->If->Then->If Dim gameLoop As Statements.DoWhile = rootSequence.Activities(1) Dim gameBody As Sequence = gameLoop.Body Dim guessCorrect As Statements.If = gameBody.Activities(2) Dim guessLow As Statements.If = guessCorrect.Then Dim tooLow As WriteLine = guessLow.Then tooLow.Text = New VisualBasicValue(Of String)("Guess.ToString() & "" is too low.""") Dim tooHigh As WriteLine = guessLow.Else tooHigh.Text = New VisualBasicValue(Of String)("Guess.ToString() & "" is too high.""") 'Create the new WriteLine that displays the closing message. Dim wl As New WriteLine() With { .Text = New VisualBasicValue(Of String) _ ("Guess.ToString() + "" is correct. You guessed it in "" & Turns.ToString() & "" turns.""") } 'Insert it as the third activity in the root sequence rootSequence.Activities.Insert(2, wl) 'Create the update map. CreateUpdateMaps(wf, "SequentialNumberGuessWorkflow.map") 'Save the updated workflow definition. SaveUpdatedDefinition(wf, "SequentialNumberGuessWorkflow_du.xaml") End Sub
private static void CreateSequentialUpdateMap() { ActivityBuilder wf = StartUpdate("SequentialNumberGuessWorkflow.xaml"); // Get a reference to the root activity in the workflow. Sequence rootSequence = wf.Implementation as Sequence; // Update the Text of the two WriteLine activities that write the // results of the user's guess. They are contained in the workflow as the // Then and Else action of the "Guess < Target" If activity. // Sequence[1]->DoWhile->Body->Sequence[2]->If->Then->If DoWhile gameLoop = rootSequence.Activities[1] as DoWhile; Sequence gameBody = gameLoop.Body as Sequence; If guessCorrect = gameBody.Activities[2] as If; If guessLow = guessCorrect.Then as If; WriteLine tooLow = guessLow.Then as WriteLine; tooLow.Text = new CSharpValue<string>("Guess.ToString() + \" is too low.\""); WriteLine tooHigh = guessLow.Else as WriteLine; tooHigh.Text = new CSharpValue<string>("Guess.ToString() + \" is too high.\""); // Add the new WriteLine that displays the closing message. WriteLine wl = new WriteLine { Text = new CSharpValue<string>("Guess.ToString() + \" is correct. You guessed it in \" + Turns.ToString() + \" turns.\"") }; // Insert it as the third activity in the root sequence rootSequence.Activities.Insert(2, wl); // Create the update map. CreateUpdateMaps(wf, "SequentialNumberGuessWorkflow.map"); // Save the updated workflow definition. SaveUpdatedDefinition(wf, "SequentialNumberGuessWorkflow_du.xaml"); }
Per compilare ed eseguire l'applicazione CreateUpdateMaps
Aggiornare il metodo
Main
e aggiungere le seguenti tre chiamate ai metodi. Questi metodi vengono aggiunti nelle sezioni riportate di seguito. Tramite ciascun metodo viene aggiornato il flusso di lavoro per determinare il numero corrispondente e viene creato un oggettoDynamicUpdateMap
mediante il quale vengono descritti gli aggiornamenti.Sub Main() 'Create the update maps for the changes needed to the v1 activities 'so they match the v2 activities. CreateSequentialUpdateMap() CreateFlowchartUpdateMap() CreateStateMachineUpdateMap() End Sub
static void Main(string[] args) { // Create the update maps for the changes needed to the v1 activities // so they match the v2 activities. CreateSequentialUpdateMap(); CreateFlowchartUpdateMap(); CreateStateMachineUpdateMap(); }
Fare clic con il pulsante destro del mouse su CreateUpdateMaps in Esplora soluzioni e scegliere Imposta come progetto di avvio.
Premere CTRL+MAIUSC+B per compilare la soluzione, quindi premere CTRL+F5 per eseguire l'applicazione
CreateUpdateMaps
.Nota
Nell'applicazione
CreateUpdateMaps
non vengono visualizzate le informazioni sullo stato durante l'esecuzione, ma se si osservano le cartelle NumberGuessWorkflowActivities_du e PreviousVersions è possibile visualizzare i file della definizione aggiornata del flusso di lavoro e i mapping di aggiornamento.Una volta creati i mapping di aggiornamento e aggiornate le definizioni del flusso di lavoro, il passaggio successivo consiste nel compilare un assembly aggiornato del flusso di lavoro contenente le definizioni aggiornate.
Per compilare l'assembly aggiornato del flusso di lavoro
Aprire una seconda istanza di Visual Studio 2012.
Scegliere Apri, quindi Progetto/Soluzione nel menu File.
Passare alla cartella NumberGuessWorkflowActivities_du creata in Procedura: Ospitare più versioni di un flusso di lavoro side-by-side, selezionare NumberGuessWorkflowActivities.csproj (o vbproj) e fare clic su Apri.
In Esplora soluzioni fare clic con il pulsante destro del mouse su SequentialNumberGuessWorkflow.xaml, quindi scegliere Escludi dal progetto. Eseguire la stessa operazione per FlowchartNumberGuessWorkflow.xaml e StateMachineNumberGuessWorkflow.xaml. Questo passaggio consente di rimuovere le versioni precedenti delle definizioni del flusso di lavoro dal progetto.
Scegliere Aggiungi elemento esistente nel menu Progetto.
Passare alla cartella NumberGuessWorkflowActivities_du creata in Procedura: Ospitare più versioni di un flusso di lavoro side-by-side.
Scegliere File XAML (*.xaml;*.xoml) nell'elenco a discesa File di tipo.
Selezionare SequentialNumberGuessWorkflow_du.xaml, FlowchartNumberGuessWorkflow_du.xaml e StateMachineNumberGuessWorkflow_du.xaml, quindi fare clic su Aggiungi.
Nota
Premere CTRL e fare clic per selezionare più elementi contemporaneamente.
Questo passaggio consente di aggiungere le versioni aggiornate delle definizioni del flusso di lavoro al progetto.
Premere CTRL+MAIUSC+B per compilare il progetto.
Scegliere Chiudi soluzione dal menu File. Non è necessario un file di soluzione per il progetto, pertanto fare clic su No per chiudere Visual Studio senza salvare un file di questo tipo. Scegliere Esci nel menu File per chiudere Visual Studio.
Aprire Esplora risorse e passare alla cartella NumberGuessWorkflowActivities_du\bin\Debug (o bin\Release a seconda delle impostazioni del progetto).
Rinominare NumberGuessWorkflowActivities.dll in NumberGuessWorkflowActivities_v15.dll e copiarlo nella cartella PreviousVersions creata in Procedura: Ospitare più versioni di un flusso di lavoro side-by-side.
Per aggiornare WorkflowVersionMap con le nuove versioni
Tornare all'istanza iniziale di Visual Studio 2012.
Fare doppio clic su WorkflowVersionMap.cs (o WorkflowVersionMap.vb) nel progetto NumberGuessWorkflowHost per aprirlo.
Aggiungere tre nuove identità del flusso di lavoro subito dopo le sei dichiarazioni di identità del flusso di lavoro esistenti. In questa esercitazione
1.5.0.0
viene usato comeWorkflowIdentity.Version
per le identità dinamiche di aggiornamento. Queste nuove identità del flusso di lavorov15
verranno usate per fornire la definizione corretta del flusso di lavoro per le istanze persistenti del flusso di lavoro aggiornate in modo dinamico.'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 'v1.5 (Dynamic Update) identities. Public StateMachineNumberGuessIdentity_v15 As WorkflowIdentity Public FlowchartNumberGuessIdentity_v15 As WorkflowIdentity Public SequentialNumberGuessIdentity_v15 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; // v1.5 (Dynamic Update) identities. static public WorkflowIdentity StateMachineNumberGuessIdentity_v15; static public WorkflowIdentity FlowchartNumberGuessIdentity_v15; static public WorkflowIdentity SequentialNumberGuessIdentity_v15;
Aggiungere il codice riportato di seguito alla fine del costruttore. Tramite questo codice vengono inizializzate le identità dinamiche del flusso di lavoro di aggiornamento, vengono caricate le definizioni del flusso di lavoro corrispondenti e vengono aggiunte queste ultime al dizionario della versione del flusso di lavoro.
'Initialize the dynamic update workflow identities. StateMachineNumberGuessIdentity_v15 = New WorkflowIdentity With { .Name = "StateMachineNumberGuessWorkflow", .Version = New Version(1, 5, 0, 0) } FlowchartNumberGuessIdentity_v15 = New WorkflowIdentity With { .Name = "FlowchartNumberGuessWorkflow", .Version = New Version(1, 5, 0, 0) } SequentialNumberGuessIdentity_v15 = New WorkflowIdentity With { .Name = "SequentialNumberGuessWorkflow", .Version = New Version(1, 5, 0, 0) } 'Add the dynamic update workflow identities to the dictionary along with 'the corresponding workflow definitions loaded from the v15 assembly. 'Assembly.LoadFile requires an absolute path so convert this relative path 'to an absolute path. Dim v15AssemblyPath As String = "..\..\..\PreviousVersions\NumberGuessWorkflowActivities_v15.dll" v15AssemblyPath = Path.GetFullPath(v15AssemblyPath) Dim v15Assembly As Assembly = Assembly.LoadFile(v15AssemblyPath) map.Add(StateMachineNumberGuessIdentity_v15, v15Assembly.CreateInstance("NumberGuessWorkflowActivities.StateMachineNumberGuessWorkflow")) map.Add(SequentialNumberGuessIdentity_v15, v15Assembly.CreateInstance("NumberGuessWorkflowActivities.SequentialNumberGuessWorkflow")) map.Add(FlowchartNumberGuessIdentity_v15, v15Assembly.CreateInstance("NumberGuessWorkflowActivities.FlowchartNumberGuessWorkflow"))
// Initialize the dynamic update workflow identities. StateMachineNumberGuessIdentity_v15 = new WorkflowIdentity { Name = "StateMachineNumberGuessWorkflow", Version = new Version(1, 5, 0, 0) }; FlowchartNumberGuessIdentity_v15 = new WorkflowIdentity { Name = "FlowchartNumberGuessWorkflow", Version = new Version(1, 5, 0, 0) }; SequentialNumberGuessIdentity_v15 = new WorkflowIdentity { Name = "SequentialNumberGuessWorkflow", Version = new Version(1, 5, 0, 0) }; // Add the dynamic update workflow identities to the dictionary along with // the corresponding workflow definitions loaded from the v15 assembly. // Assembly.LoadFile requires an absolute path so convert this relative path // to an absolute path. string v15AssemblyPath = @"..\..\..\PreviousVersions\NumberGuessWorkflowActivities_v15.dll"; v15AssemblyPath = Path.GetFullPath(v15AssemblyPath); Assembly v15Assembly = Assembly.LoadFile(v15AssemblyPath); map.Add(StateMachineNumberGuessIdentity_v15, v15Assembly.CreateInstance("NumberGuessWorkflowActivities.StateMachineNumberGuessWorkflow") as Activity); map.Add(SequentialNumberGuessIdentity_v15, v15Assembly.CreateInstance("NumberGuessWorkflowActivities.SequentialNumberGuessWorkflow") as Activity); map.Add(FlowchartNumberGuessIdentity_v15, v15Assembly.CreateInstance("NumberGuessWorkflowActivities.FlowchartNumberGuessWorkflow") as Activity);
Nell'esempio seguente viene mostrata la classe
WorkflowVersionMap
completata.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 'v1.5 (Dynamic Update) identities. Public StateMachineNumberGuessIdentity_v15 As WorkflowIdentity Public FlowchartNumberGuessIdentity_v15 As WorkflowIdentity Public SequentialNumberGuessIdentity_v15 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")) 'Initialize the dynamic update workflow identities. StateMachineNumberGuessIdentity_v15 = New WorkflowIdentity With { .Name = "StateMachineNumberGuessWorkflow", .Version = New Version(1, 5, 0, 0) } FlowchartNumberGuessIdentity_v15 = New WorkflowIdentity With { .Name = "FlowchartNumberGuessWorkflow", .Version = New Version(1, 5, 0, 0) } SequentialNumberGuessIdentity_v15 = New WorkflowIdentity With { .Name = "SequentialNumberGuessWorkflow", .Version = New Version(1, 5, 0, 0) } 'Add the dynamic update workflow identities to the dictionary along with 'the corresponding workflow definitions loaded from the v15 assembly. 'Assembly.LoadFile requires an absolute path so convert this relative path 'to an absolute path. Dim v15AssemblyPath As String = "..\..\..\PreviousVersions\NumberGuessWorkflowActivities_v15.dll" v15AssemblyPath = Path.GetFullPath(v15AssemblyPath) Dim v15Assembly As Assembly = Assembly.LoadFile(v15AssemblyPath) map.Add(StateMachineNumberGuessIdentity_v15, v15Assembly.CreateInstance("NumberGuessWorkflowActivities.StateMachineNumberGuessWorkflow")) map.Add(SequentialNumberGuessIdentity_v15, v15Assembly.CreateInstance("NumberGuessWorkflowActivities.SequentialNumberGuessWorkflow")) map.Add(FlowchartNumberGuessIdentity_v15, v15Assembly.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; // v1.5 (Dynamic Update) identities. static public WorkflowIdentity StateMachineNumberGuessIdentity_v15; static public WorkflowIdentity FlowchartNumberGuessIdentity_v15; static public WorkflowIdentity SequentialNumberGuessIdentity_v15; 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); // Initialize the dynamic update workflow identities. StateMachineNumberGuessIdentity_v15 = new WorkflowIdentity { Name = "StateMachineNumberGuessWorkflow", Version = new Version(1, 5, 0, 0) }; FlowchartNumberGuessIdentity_v15 = new WorkflowIdentity { Name = "FlowchartNumberGuessWorkflow", Version = new Version(1, 5, 0, 0) }; SequentialNumberGuessIdentity_v15 = new WorkflowIdentity { Name = "SequentialNumberGuessWorkflow", Version = new Version(1, 5, 0, 0) }; // Add the dynamic update workflow identities to the dictionary along with // the corresponding workflow definitions loaded from the v15 assembly. // Assembly.LoadFile requires an absolute path so convert this relative path // to an absolute path. string v15AssemblyPath = @"..\..\..\PreviousVersions\NumberGuessWorkflowActivities_v15.dll"; v15AssemblyPath = Path.GetFullPath(v15AssemblyPath); Assembly v15Assembly = Assembly.LoadFile(v15AssemblyPath); map.Add(StateMachineNumberGuessIdentity_v15, v15Assembly.CreateInstance("NumberGuessWorkflowActivities.StateMachineNumberGuessWorkflow") as Activity); map.Add(SequentialNumberGuessIdentity_v15, v15Assembly.CreateInstance("NumberGuessWorkflowActivities.SequentialNumberGuessWorkflow") as Activity); map.Add(FlowchartNumberGuessIdentity_v15, v15Assembly.CreateInstance("NumberGuessWorkflowActivities.FlowchartNumberGuessWorkflow") as Activity); } public static Activity GetWorkflowDefinition(WorkflowIdentity identity) { return map[identity]; } public static string GetIdentityDescription(WorkflowIdentity identity) { return identity.ToString(); } }
Premere CTRL+MAIUSC+B per compilare il progetto.
Per applicare gli aggiornamenti dinamici
Fare clic con il pulsante destro del mouse su WF45GettingStartedTutorial in Esplora soluzioni e scegliere Aggiungi, Nuovo progetto.
Nel nodo Installato selezionare Visual C#, Windows (o Visual Basic, Windows).
Nota
A seconda del linguaggio di programmazione configurato come linguaggio principale in Visual Studio, sotto il nodo Altri linguaggi del nodo Installato viene visualizzato il nodo Visual C# o Visual Basic .
Assicurarsi che nell'elenco a discesa della versione di .NET Framework sia selezionata l'opzione .NET Framework 4.5 . Selezionare Applicazione console dall'elenco Windows. Digitare ApplyDynamicUpdate nella casella Nome, quindi scegliere OK.
Fare clic con il pulsante destro del mouse su ApplyDynamicUpdate in Esplora soluzioni e scegliere Aggiungi riferimento.
Fare clic su Soluzione e selezionare la casella accanto a NumberGuessWorkflowHost. Questo riferimento è necessario affinché la classe
ApplyDynamicUpdate
possa essere usata dall'oggettoNumberGuessWorkflowHost.WorkflowVersionMap
.Selezionare Framework dal nodo Assembly nell'elenco Aggiungi riferimento. Digitare System.Activities nella casella Cerca assembly. Gli assembly verranno filtrati e sarà più semplice selezionare i riferimenti desiderati.
Selezionare la casella di controllo accanto a System.Activities nell'elenco Risultati ricerca.
Digitare Serializzazione nella casella Cerca assembly e selezionare la casella di controllo accanto a System.Runtime.Serialization nell'elenco Risultati ricerca.
Digitare DurableInstancing nella casella Cerca assembly e selezionare la casella di controllo accanto a System.Activities.DurableInstancing e System.Runtime.DurableInstancing nell'elenco Risultati ricerca.
Fare clic su OK per chiudere Gestione riferimenti e aggiungere i riferimenti.
Fare clic con il pulsante destro del mouse su ApplyDynamicUpdate in Esplora soluzioni e scegliere Aggiungi, quindi Classe. Digitare
DynamicUpdateInfo
nella casella Nome e fare clic su Aggiungi.Aggiungere i due membri riportati di seguito alla classe
DynamicUpdateInfo
. Nell'esempio seguente viene mostrata la classeDynamicUpdateInfo
completata. In questa classe sono contenute le informazioni sul mapping di aggiornamento e la nuova identità del flusso di lavoro usata quando un'istanza del flusso di lavoro viene aggiornata.Public Class DynamicUpdateInfo Public updateMap As DynamicUpdateMap Public newIdentity As WorkflowIdentity End Class
class DynamicUpdateInfo { public DynamicUpdateMap updateMap; public WorkflowIdentity newIdentity; }
Aggiungere le seguenti istruzioni
using
(oImports
) nella parte superiore del file con le altre istruzioniusing
(oImports
).Imports System.Activities Imports System.Activities.DynamicUpdate
using System.Activities; using System.Activities.DynamicUpdate;
Fare doppio clic su Program.cs (o Module1.vb) in Esplora soluzioni.
Aggiungere le seguenti istruzioni
using
(oImports
) nella parte superiore del file con le altre istruzioniusing
(oImports
).Imports NumberGuessWorkflowHost Imports System.Data.SqlClient Imports System.Activities.DynamicUpdate Imports System.IO Imports System.Runtime.Serialization Imports System.Activities Imports System.Activities.DurableInstancing
using NumberGuessWorkflowHost; using System.Data; using System.Data.SqlClient; using System.Activities; using System.Activities.DynamicUpdate; using System.IO; using System.Runtime.Serialization; using System.Activities.DurableInstancing;
Aggiungere il membro della stringa di connessione seguente alla classe
Program
(oModule1
).Const connectionString = "Server=.\SQLEXPRESS;Initial Catalog=WF45GettingStartedTutorial;Integrated Security=SSPI"
const string connectionString = "Server=.\\SQLEXPRESS;Initial Catalog=WF45GettingStartedTutorial;Integrated Security=SSPI";
Importante
Microsoft consiglia di usare il flusso di autenticazione più sicuro disponibile. Se ci si connette ad Azure SQL, le Identità gestite per le risorse Azure sono il metodo di autenticazione consigliato.
Nota
Il nome del server della stringa di connessione potrebbe essere diverso a seconda dell'edizione di SQL Server.
Aggiungere il seguente metodo
GetIDs
alla classeProgram
(oModule1
). Questo metodo restituisce un elenco di ID persistenti dell'istanza del flusso di lavoro.Function GetIds() As IList(Of Guid) Dim Ids As New List(Of Guid) Dim localCmd = _ String.Format("Select [InstanceId] from [System.Activities.DurableInstancing].[Instances] Order By [CreationTime]") Using localCon = New SqlConnection(connectionString) Dim cmd As SqlCommand = localCon.CreateCommand() cmd.CommandText = localCmd localCon.Open() Using reader = cmd.ExecuteReader(CommandBehavior.CloseConnection) While reader.Read() 'Get the InstanceId of the persisted Workflow Dim id As Guid = Guid.Parse(reader(0).ToString()) 'Add it to the list. Ids.Add(id) End While End Using End Using Return Ids End Function
static IList<Guid> GetIds() { List<Guid> Ids = new List<Guid>(); string localCmd = string.Format("Select [InstanceId] from [System.Activities.DurableInstancing].[Instances] Order By [CreationTime]"); using (SqlConnection localCon = new SqlConnection(connectionString)) { SqlCommand cmd = localCon.CreateCommand(); cmd.CommandText = localCmd; localCon.Open(); using (SqlDataReader reader = cmd.ExecuteReader(CommandBehavior.CloseConnection)) { while (reader.Read()) { // Get the InstanceId of the persisted Workflow Guid id = Guid.Parse(reader[0].ToString()); // Add it to the list. Ids.Add(id); } } } return Ids; }
Aggiungere il seguente metodo
LoadMap
alla classeProgram
(oModule1
). Questo metodo consente di creare un dizionario tramite cui viene eseguito il mapping delle identità del flusso di lavorov1
ai mapping di aggiornamento e alle nuove identità del flusso di lavoro usate per aggiornare le istanze corrispondenti del flusso di lavoro persistente.Function LoadMap(mapName As String) As DynamicUpdateMap Dim mapPath As String = Path.Combine("..\..\..\PreviousVersions", mapName) Dim map As DynamicUpdateMap Using fs As FileStream = File.Open(mapPath, FileMode.Open) Dim serializer As DataContractSerializer = New DataContractSerializer(GetType(DynamicUpdateMap)) Dim updateMap = serializer.ReadObject(fs) If updateMap Is Nothing Then Throw New ApplicationException("DynamicUpdateMap is null.") End If map = updateMap End Using Return map End Function
static DynamicUpdateMap LoadMap(string mapName) { string path = Path.Combine(@"..\..\..\PreviousVersions", mapName); DynamicUpdateMap map; using (FileStream fs = File.Open(path, FileMode.Open)) { DataContractSerializer serializer = new DataContractSerializer(typeof(DynamicUpdateMap)); object updateMap = serializer.ReadObject(fs); if (updateMap == null) { throw new ApplicationException("DynamicUpdateMap is null."); } map = updateMap as DynamicUpdateMap; } return map; }
Aggiungere il seguente metodo
LoadMaps
alla classeProgram
(oModule1
). Tramite questo metodo vengono caricati i tre mapping di aggiornamento e viene creato un dizionario mediante il quale viene eseguito il mapping delle identità del flusso di lavorov1
ai mapping di aggiornamento.Function LoadMaps() As IDictionary(Of WorkflowIdentity, DynamicUpdateInfo) 'There are 3 update maps to describe the changes to update v1 workflows, 'one for reach of the 3 workflow types in the tutorial. Dim maps = New Dictionary(Of WorkflowIdentity, DynamicUpdateInfo)() Dim sequentialMap As DynamicUpdateMap = LoadMap("SequentialNumberGuessWorkflow.map") Dim sequentialInfo = New DynamicUpdateInfo With { .updateMap = sequentialMap, .newIdentity = WorkflowVersionMap.SequentialNumberGuessIdentity_v15 } maps.Add(WorkflowVersionMap.SequentialNumberGuessIdentity_v1, sequentialInfo) Dim stateMap As DynamicUpdateMap = LoadMap("StateMachineNumberGuessWorkflow.map") Dim stateInfo = New DynamicUpdateInfo With { .updateMap = stateMap, .newIdentity = WorkflowVersionMap.StateMachineNumberGuessIdentity_v15 } maps.Add(WorkflowVersionMap.StateMachineNumberGuessIdentity_v1, stateInfo) Dim flowchartMap As DynamicUpdateMap = LoadMap("FlowchartNumberGuessWorkflow.map") Dim flowchartInfo = New DynamicUpdateInfo With { .updateMap = flowchartMap, .newIdentity = WorkflowVersionMap.FlowchartNumberGuessIdentity_v15 } maps.Add(WorkflowVersionMap.FlowchartNumberGuessIdentity_v1, flowchartInfo) Return maps End Function
static IDictionary<WorkflowIdentity, DynamicUpdateInfo> LoadMaps() { // There are 3 update maps to describe the changes to update v1 workflows, // one for reach of the 3 workflow types in the tutorial. Dictionary<WorkflowIdentity, DynamicUpdateInfo> maps = new Dictionary<WorkflowIdentity, DynamicUpdateInfo>(); DynamicUpdateMap sequentialMap = LoadMap("SequentialNumberGuessWorkflow.map"); DynamicUpdateInfo sequentialInfo = new DynamicUpdateInfo { updateMap = sequentialMap, newIdentity = WorkflowVersionMap.SequentialNumberGuessIdentity_v15 }; maps.Add(WorkflowVersionMap.SequentialNumberGuessIdentity_v1, sequentialInfo); DynamicUpdateMap stateMap = LoadMap("StateMachineNumberGuessWorkflow.map"); DynamicUpdateInfo stateInfo = new DynamicUpdateInfo { updateMap = stateMap, newIdentity = WorkflowVersionMap.StateMachineNumberGuessIdentity_v15 }; maps.Add(WorkflowVersionMap.StateMachineNumberGuessIdentity_v1, stateInfo); DynamicUpdateMap flowchartMap = LoadMap("FlowchartNumberGuessWorkflow.map"); DynamicUpdateInfo flowchartInfo = new DynamicUpdateInfo { updateMap = flowchartMap, newIdentity = WorkflowVersionMap.FlowchartNumberGuessIdentity_v15 }; maps.Add(WorkflowVersionMap.FlowchartNumberGuessIdentity_v1, flowchartInfo); return maps; }
Aggiungere il codice seguente a
Main
. Con questo codice è possibile scorrere le istanze del flusso di lavoro persistente ed esaminare ogni oggettoWorkflowIdentity
. Se tramiteWorkflowIdentity
viene eseguito il mapping a un'istanza del flusso di lavorov1
, un oggettoWorkflowApplication
è configurato con la definizione aggiornata del flusso di lavoro e un'identità aggiornata del flusso di lavoro. Successivamente, l'oggettoWorkflowApplication.Load
viene chiamato con l'istanza e il mapping di aggiornamento, con cui è possibile applicare il mapping di aggiornamento dinamico. Una volta applicato l'aggiornamento, l'istanza aggiornata è persistente con una chiamata aUnload
.Dim store = New SqlWorkflowInstanceStore(connectionString) WorkflowApplication.CreateDefaultInstanceOwner(store, Nothing, WorkflowIdentityFilter.Any) Dim updateMaps As IDictionary(Of WorkflowIdentity, DynamicUpdateInfo) = LoadMaps() For Each id As Guid In GetIds() 'Get a proxy to the instance. Dim instance As WorkflowApplicationInstance = WorkflowApplication.GetInstance(id, store) Console.WriteLine("Inspecting: {0}", instance.DefinitionIdentity) 'Only update v1 workflows. If Not instance.DefinitionIdentity Is Nothing AndAlso _ instance.DefinitionIdentity.Version.Equals(New Version(1, 0, 0, 0)) Then Dim info As DynamicUpdateInfo = updateMaps(instance.DefinitionIdentity) 'Associate the persisted WorkflowApplicationInstance with 'a WorkflowApplication that is configured with the updated 'definition and updated WorkflowIdentity. Dim wf As Activity = WorkflowVersionMap.GetWorkflowDefinition(info.newIdentity) Dim wfApp = New WorkflowApplication(wf, info.newIdentity) 'Apply the Dynamic Update. wfApp.Load(instance, info.updateMap) 'Persist the updated instance. wfApp.Unload() Console.WriteLine("Updated to: {0}", info.newIdentity) Else 'Not updating this instance, so unload it. instance.Abandon() End If Next
SqlWorkflowInstanceStore store = new SqlWorkflowInstanceStore(connectionString); WorkflowApplication.CreateDefaultInstanceOwner(store, null, WorkflowIdentityFilter.Any); IDictionary<WorkflowIdentity, DynamicUpdateInfo> updateMaps = LoadMaps(); foreach (Guid id in GetIds()) { // Get a proxy to the instance. WorkflowApplicationInstance instance = WorkflowApplication.GetInstance(id, store); Console.WriteLine("Inspecting: {0}", instance.DefinitionIdentity); // Only update v1 workflows. if (instance.DefinitionIdentity != null && instance.DefinitionIdentity.Version.Equals(new Version(1, 0, 0, 0))) { DynamicUpdateInfo info = updateMaps[instance.DefinitionIdentity]; // Associate the persisted WorkflowApplicationInstance with // a WorkflowApplication that is configured with the updated // definition and updated WorkflowIdentity. Activity wf = WorkflowVersionMap.GetWorkflowDefinition(info.newIdentity); WorkflowApplication wfApp = new WorkflowApplication(wf, info.newIdentity); // Apply the Dynamic Update. wfApp.Load(instance, info.updateMap); // Persist the updated instance. wfApp.Unload(); Console.WriteLine("Updated to: {0}", info.newIdentity); } else { // Not updating this instance, so unload it. instance.Abandon(); } }
Fare clic con il pulsante destro del mouse su ApplyDynamicUpdate in Esplora soluzioni e scegliere Imposta come progetto di avvio.
Premere Ctrl+MAIUSC+B per compilare la soluzione, quindi premere Ctrl+F5 per eseguire l'applicazione
ApplyDynamicUpdate
e aggiornare le istanze del flusso di lavoro persistente. L'output dovrebbe essere simile al seguente. I flussi di lavoro della versione 1.0.0.0 vengono aggiornati alla versione 1.5.0.0, mentre i flussi di lavoro della versione 2.0.0.0 non vengono aggiornati.Inspecting: StateMachineNumberGuessWorkflow; Version=1.0.0.0
Updated to: StateMachineNumberGuessWorkflow; Version=1.5.0.0
Inspecting: StateMachineNumberGuessWorkflow; Version=1.0.0.0
Updated to: StateMachineNumberGuessWorkflow; Version=1.5.0.0
Inspecting: FlowchartNumberGuessWorkflow; Version=1.0.0.0
Updated to: FlowchartNumberGuessWorkflow; Version=1.5.0.0
Inspecting: FlowchartNumberGuessWorkflow; Version=1.0.0.0
Updated to: FlowchartNumberGuessWorkflow; Version=1.5.0.0
Inspecting: SequentialNumberGuessWorkflow; Version=1.0.0.0
Updated to: SequentialNumberGuessWorkflow; Version=1.5.0.0
Inspecting: SequentialNumberGuessWorkflow; Version=1.0.0.0
Updated to: SequentialNumberGuessWorkflow; Version=1.5.0.0
Inspecting: SequentialNumberGuessWorkflow; Version=1.0.0.0
Updated to: SequentialNumberGuessWorkflow; Version=1.5.0.0
Inspecting: StateMachineNumberGuessWorkflow; Version=1.0.0.0
Updated to: StateMachineNumberGuessWorkflow; Version=1.5.0.0
Inspecting: FlowchartNumberGuessWorkflow; Version=1.0.0.0
Updated to: FlowchartNumberGuessWorkflow; Version=1.5.0.0
Inspecting: StateMachineNumberGuessWorkflow; Version=2.0.0.0
Inspecting: StateMachineNumberGuessWorkflow; Version=2.0.0.0
Inspecting: FlowchartNumberGuessWorkflow; Version=2.0.0.0
Inspecting: FlowchartNumberGuessWorkflow; Version=2.0.0.0
Inspecting: SequentialNumberGuessWorkflow; Version=2.0.0.0
Inspecting: SequentialNumberGuessWorkflow; Version=2.0.0.0
Premere un tasto qualsiasi per continuare. . .
Per eseguire l'applicazione con i flussi di lavoro aggiornati
Fare clic con il pulsante destro del mouse su NumberGuessWorkflowHost in Esplora soluzioni e scegliere Imposta come progetto di avvio.
Premere CTRL+F5 per eseguire l'applicazione.
Fare clic su Nuova partita per avviare un nuovo flusso di lavoro. Si notino le informazioni sulla versione sotto la finestra di stato indicanti che si tratta di un flusso di lavoro
v2
.Selezionare uno dei flussi di lavoro
v1
avviati all'inizio dell'argomento Procedura: Ospitare più versioni di un flusso di lavoro side-by-Side. Si noti che le informazioni sulla versione nella finestra di stato indicano che la versione del flusso di lavoro è 1.5.0.0. Si noti inoltre che non sono disponibili informazioni sui tentativi precedenti, eccetto se troppo alti o troppo bassi.Immettere un numero compreso tra 1 e 10
Il tentativo è troppo basso.Prendere nota dell'oggetto
InstanceId
, quindi immettere dei tentativi finché il flusso di lavoro non viene completato. Nella finestra di stato vengono visualizzate le informazioni sul contenuto del tentativo, dal momento che le attivitàWriteLine
sono state aggiornate dall'aggiornamento dinamico.Immettere un numero compreso tra 1 e 10
Il tentativo è troppo basso.
Immettere un numero compreso tra 1 e 10
5 è troppo basso.
Immettere un numero compreso tra 1 e 10
7 è troppo alto.
Immettere un numero compreso tra 1 e 10
Congratulazioni, hai indovinato il numero con 4 tentativi.Aprire Esplora risorse e passare alla cartella NumberGuessWorkflowHost\bin\debug (o bin\release a seconda delle impostazioni del progetto), quindi aprire il file di rilevamento mediante Blocco note corrispondente al flusso di lavoro completato. Se non si è presa nota dell'oggetto
InstanceId
, è possibile identificare il file di rilevamento corretto usando le informazioni in Data ultima modifica in Esplora risorse. Nell'ultima riga delle informazioni di rilevamento è contenuto l'output dell'attivitàWriteLine
appena aggiunta.Immettere un numero compreso tra 1 e 10
Il tentativo è troppo basso.
Immettere un numero compreso tra 1 e 10
5 è troppo basso.
Immettere un numero compreso tra 1 e 10
7 è troppo alto.
Immettere un numero compreso tra 1 e 10
6 è corretto. Hai indovinato con 4 tentativi.
Per attivare le versioni precedenti di avvio dei flussi di lavoro
Se si esauriscono i flussi di lavoro da aggiornare, è possibile modificare l'applicazione NumberGuessWorkflowHost
per abilitare l'avvio delle versioni precedenti dei flussi di lavoro.
Fare doppio clic WorkflowHostForm in Esplora soluzioni e selezionare la casella combinata di WorkflowType.
Nella finestra Proprietà, selezionare la proprietà Elementi e fare clic sul pulsante con i puntini di sospensione per modificare la raccolta Elementi.
Aggiungere alla raccolta i seguenti tre elementi.
StateMachineNumberGuessWorkflow v1 FlowchartNumberGuessWorkflow v1 SequentialNumberGuessWorkflow v1
La raccolta
Items
completata avrà sei elementi.StateMachineNumberGuessWorkflow FlowchartNumberGuessWorkflow SequentialNumberGuessWorkflow StateMachineNumberGuessWorkflow v1 FlowchartNumberGuessWorkflow v1 SequentialNumberGuessWorkflow v1
Fare doppio clic su WorkflowHostForm in Esplora soluzioni e selezionare Visualizza codice.
Aggiungere tre nuovi casi all'istruzione
switch
(oSelect Case
) nel gestore diNewGame_Click
per eseguire il mapping dei nuovi elementi della casella combinata di WorkflowType alle identità corrispondenti di flusso di lavoro.Case "SequentialNumberGuessWorkflow v1" identity = WorkflowVersionMap.SequentialNumberGuessIdentity_v1 Case "StateMachineNumberGuessWorkflow v1" identity = WorkflowVersionMap.StateMachineNumberGuessIdentity_v1 Case "FlowchartNumberGuessWorkflow v1" identity = WorkflowVersionMap.FlowchartNumberGuessIdentity_v1
case "SequentialNumberGuessWorkflow v1": identity = WorkflowVersionMap.SequentialNumberGuessIdentity_v1; break; case "StateMachineNumberGuessWorkflow v1": identity = WorkflowVersionMap.StateMachineNumberGuessIdentity_v1; break; case "FlowchartNumberGuessWorkflow v1": identity = WorkflowVersionMap.FlowchartNumberGuessIdentity_v1; break;
L'esempio riportato di seguito contiene l'istruzione completa
switch
(oSelect Case
).Select Case WorkflowType.SelectedItem.ToString() Case "SequentialNumberGuessWorkflow" identity = WorkflowVersionMap.SequentialNumberGuessIdentity Case "StateMachineNumberGuessWorkflow" identity = WorkflowVersionMap.StateMachineNumberGuessIdentity Case "FlowchartNumberGuessWorkflow" identity = WorkflowVersionMap.FlowchartNumberGuessIdentity Case "SequentialNumberGuessWorkflow v1" identity = WorkflowVersionMap.SequentialNumberGuessIdentity_v1 Case "StateMachineNumberGuessWorkflow v1" identity = WorkflowVersionMap.StateMachineNumberGuessIdentity_v1 Case "FlowchartNumberGuessWorkflow v1" identity = WorkflowVersionMap.FlowchartNumberGuessIdentity_v1 End Select
switch (WorkflowType.SelectedItem.ToString()) { case "SequentialNumberGuessWorkflow": identity = WorkflowVersionMap.SequentialNumberGuessIdentity; break; case "StateMachineNumberGuessWorkflow": identity = WorkflowVersionMap.StateMachineNumberGuessIdentity; break; case "FlowchartNumberGuessWorkflow": identity = WorkflowVersionMap.FlowchartNumberGuessIdentity; break; case "SequentialNumberGuessWorkflow v1": identity = WorkflowVersionMap.SequentialNumberGuessIdentity_v1; break; case "StateMachineNumberGuessWorkflow v1": identity = WorkflowVersionMap.StateMachineNumberGuessIdentity_v1; break; case "FlowchartNumberGuessWorkflow v1": identity = WorkflowVersionMap.FlowchartNumberGuessIdentity_v1; break; };
Premere CTRL+F5 per compilare ed eseguire l'applicazione. È possibile avviare le versioni
v1
del flusso di lavoro nonché le versioni correnti. Per aggiornare dinamicamente le nuove istanze, eseguire l'applicazione di ApplyDynamicUpdate.