Een langlopende werkstroom maken en uitvoeren
Een van de centrale functies van Windows Workflow Foundation (WF) is de mogelijkheid van de runtime om niet-actieve werkstromen in een database te behouden en te verwijderen. De stappen in Procedure: Een werkstroom uitvoeren heeft de basisbeginselen van het hosten van werkstromen gedemonstreerd met behulp van een consoletoepassing. Voorbeelden zijn weergegeven van beginwerkstromen, werkstroomlevenscyclushandlers en het hervatten van bladwijzers. Om de werkstroompersistentie effectief te demonstreren, is een complexere werkstroomhost vereist die ondersteuning biedt voor het starten en hervatten van meerdere werkstroomexemplaren. Deze stap in de zelfstudie laat zien hoe u een Windows-formulierhosttoepassing maakt die ondersteuning biedt voor het starten en hervatten van meerdere werkstroomexemplaren, werkstroompersistentie en biedt een basis voor de geavanceerde functies, zoals bijhouden en versiebeheer die worden gedemonstreerd in de volgende zelfstudiestappen.
Notitie
In deze zelfstudiestap en de volgende stappen worden alle drie de werkstroomtypen gebruikt: Een werkstroom maken.
De persistentiedatabase maken
Open SQL Server Management Studio en maak verbinding met de lokale server, bijvoorbeeld .\SQLEXPRESS. Klik met de rechtermuisknop op het knooppunt Databases op de lokale server en selecteer Nieuwe database. Geef de nieuwe database de naam WF45GettingStartedTutorial, accepteer alle andere waarden en selecteer OK.
Notitie
Zorg ervoor dat u de machtiging Database maken hebt op de lokale server voordat u de database maakt.
Kies Openen, Bestand in het menu Bestand . Blader naar de volgende map: C:\Windows\Microsoft.NET\Framework\v4.0.30319\sql\en
Selecteer de volgende twee bestanden en klik op Openen.
SqlWorkflowInstanceStoreLogic.sql
SqlWorkflowInstanceStoreSchema.sql
Kies SqlWorkflowInstanceStoreSchema.sql in het menu Venster . Zorg ervoor dat WF45GettingStartedTutorial is geselecteerd in de vervolgkeuzelijst Beschikbare databases en kies Uitvoeren in het menu Query.
Kies SqlWorkflowInstanceStoreLogic.sql in het menu Venster . Zorg ervoor dat WF45GettingStartedTutorial is geselecteerd in de vervolgkeuzelijst Beschikbare databases en kies Uitvoeren in het menu Query.
Waarschuwing
Het is belangrijk om de vorige twee stappen in de juiste volgorde uit te voeren. Als de query's niet op volgorde worden uitgevoerd, treden er fouten op en is de persistentiedatabase niet juist geconfigureerd.
De verwijzing naar de DurableInstancing-assembly's toevoegen
Klik met de rechtermuisknop op NumberGuessWorkflowHost in Solution Explorer en selecteer Verwijzing toevoegen.
Selecteer Assembly's in de lijst Verwijzing toevoegen en typ
DurableInstancing
in het vak Zoekassembly's . Hierdoor worden de assembly's gefilterd en kunnen de gewenste verwijzingen gemakkelijker worden geselecteerd.Schakel het selectievakje naast System.Activities.DurableInstancing en System.Runtime.DurableInstancing in de lijst met zoekresultaten in en klik op OK.
Het hostformulier voor de werkstroom maken
Klik met de rechtermuisknop op NumberGuessWorkflowHost in Solution Explorer en kies Toevoegen, Nieuw item.
Kies Windows-formulier in de lijst geïnstalleerde sjablonen, typ
WorkflowHostForm
het vak Naam en klik op Toevoegen.Configureer de volgende eigenschappen op het formulier.
Eigenschappen Weergegeven als FormBorderStyle FixedSingle MaximaliseerBox Onwaar Tekengrootte 400, 420 Voeg de volgende besturingselementen toe aan het formulier in de opgegeven volgorde en configureer de eigenschappen zoals omgeleid.
Control Eigenschap: waarde Knop Naam: NewGame
Locatie: 13, 13
Grootte: 75, 23
Tekst: Nieuw spelLabel Locatie: 94, 18
Tekst: Een getal raden van 1 totKeuzelijst met invoervak Naam: NumberRange
DropDownStyle: DropDownList
Items: 10, 100, 1000
Locatie: 228, 12
Grootte: 143, 21Label Locatie: 13, 43
Tekst: werkstroomtypeKeuzelijst met invoervak Naam: WorkflowType
DropDownStyle: DropDownList
Items: StateMachineNumberGuessWorkflow, FlowchartNumberGuessWorkflow, SequentialNumberGuessWorkflow
Locatie: 94, 40
Grootte: 277, 21Label Naam: WorkflowVersion
Locatie: 13, 362
Tekst: werkstroomversieGroepsvak Locatie: 13, 67
Grootte: 358, 287
Tekst: GameNotitie
Wanneer u de volgende besturingselementen toevoegt, plaatst u deze in het groepsvak.
Control Eigenschap: waarde Label Locatie: 7, 20
Tekst: Id van werkstroomexemplarenKeuzelijst met invoervak Naam: InstanceId
DropDownStyle: DropDownList
Locatie: 121, 17
Grootte: 227, 21Label Locatie: 7, 47
Tekst: SchattingTextBox Naam: Schatting
Locatie: 50, 44
Grootte: 65, 20Knop Naam: EnterGuess
Locatie: 121, 42
Grootte: 75, 23
Tekst: Schatting invoerenKnop Naam: QuitGame
Locatie: 274, 42
Grootte: 75, 23
Tekst: AfsluitenTextBox Naam: WorkflowStatus
Locatie: 10, 73
Multiline: Waar
Alleen-lezen: Waar
Schuifbalken: verticaal
Grootte: 338, 208Stel de eigenschap AcceptButton van het formulier in op EnterGuess.
In het volgende voorbeeld ziet u het ingevulde formulier.
De eigenschappen en helpermethoden van het formulier toevoegen
Met de stappen in deze sectie worden eigenschappen en helpermethoden toegevoegd aan de formulierklasse waarmee de gebruikersinterface van het formulier wordt geconfigureerd ter ondersteuning van actieve en hervatting van werkstromen voor het raden van getallen.
Klik met de rechtermuisknop op WorkflowHostForm in Solution Explorer en kies Code weergeven.
Voeg de volgende
using
(ofImports
) instructies toe boven aan het bestand met de andereusing
(ofImports
) instructies.Imports System.Activities Imports System.Activities.DurableInstancing Imports System.Data.SqlClient Imports System.IO Imports System.Windows.Forms
using System.Activities; using System.Activities.DurableInstancing; using System.Data.SqlClient; using System.IO; using System.Windows.Forms;
Voeg de volgende liddeclaraties toe aan de klasse WorkflowHostForm .
Belangrijk
Microsoft raadt u aan de veiligste verificatiestroom te gebruiken die beschikbaar is. Als u verbinding maakt met Azure SQL, is Managed Identities voor Azure-resources de aanbevolen verificatiemethode.
Const connectionString = "Server=.\SQLEXPRESS;Initial Catalog=WF45GettingStartedTutorial;Integrated Security=SSPI" Dim store As SqlWorkflowInstanceStore Dim workflowStarting As Boolean
const string connectionString = "Server=.\\SQLEXPRESS;Initial Catalog=WF45GettingStartedTutorial;Integrated Security=SSPI"; SqlWorkflowInstanceStore store; bool workflowStarting;
Notitie
Als uw verbindingsreeks anders is, werkt
connectionString
u deze bij om naar uw database te verwijzen.Voeg een
WorkflowInstanceId
eigenschap toe aan deWorkflowFormHost
klasse.Public ReadOnly Property WorkflowInstanceId() As Guid Get If InstanceId.SelectedIndex = -1 Then Return Guid.Empty Else Return New Guid(InstanceId.SelectedItem.ToString()) End If End Get End Property
public Guid WorkflowInstanceId { get { return InstanceId.SelectedIndex == -1 ? Guid.Empty : (Guid)InstanceId.SelectedItem; } }
De
InstanceId
keuzelijst met invoervak bevat een lijst met persistente werkstroomexemplaren en deWorkflowInstanceId
eigenschap retourneert de momenteel geselecteerde werkstroom.Voeg een handler toe voor de formulier
Load
gebeurtenis. Als u de handler wilt toevoegen, schakelt u over naar de ontwerpweergave voor het formulier, klikt u op het pictogram Gebeurtenissen boven aan het venster Eigenschappen en dubbelklikt u op Laden.Private Sub WorkflowHostForm_Load(sender As Object, e As EventArgs) Handles Me.Load End Sub
private void WorkflowHostForm_Load(object sender, EventArgs e) { }
Voeg de volgende code toe aan
WorkflowHostForm_Load
.' Initialize the store and configure it so that it can be used for ' multiple WorkflowApplication instances. store = New SqlWorkflowInstanceStore(connectionString) WorkflowApplication.CreateDefaultInstanceOwner(store, Nothing, WorkflowIdentityFilter.Any) ' Set default ComboBox selections. NumberRange.SelectedIndex = 0 WorkflowType.SelectedIndex = 0 ListPersistedWorkflows()
// Initialize the store and configure it so that it can be used for // multiple WorkflowApplication instances. store = new SqlWorkflowInstanceStore(connectionString); WorkflowApplication.CreateDefaultInstanceOwner(store, null, WorkflowIdentityFilter.Any); // Set default ComboBox selections. NumberRange.SelectedIndex = 0; WorkflowType.SelectedIndex = 0; ListPersistedWorkflows();
Wanneer het formulier wordt geladen, worden de
SqlWorkflowInstanceStore
keuzelijsten met invoervakbereik en werkstroomtype ingesteld op standaardwaarden en worden de persistente werkstroomexemplaren toegevoegd aan deInstanceId
keuzelijst met invoervak.Voeg een
SelectedIndexChanged
handler toe voorInstanceId
. Als u de handler wilt toevoegen, schakelt u over naar de ontwerpweergave voor het formulier, selecteert u deInstanceId
keuzelijst met invoervak, klikt u op het pictogram Gebeurtenissen boven aan het venster Eigenschappen en dubbelklikt u op SelectedIndexChanged.Private Sub InstanceId_SelectedIndexChanged(sender As Object, e As EventArgs) Handles InstanceId.SelectedIndexChanged End Sub
private void InstanceId_SelectedIndexChanged(object sender, EventArgs e) { }
Voeg de volgende code toe aan
InstanceId_SelectedIndexChanged
. Wanneer de gebruiker een werkstroom selecteert met behulp van de keuzelijst met invoervak, wordt het statusvenster bijgewerkt.If InstanceId.SelectedIndex = -1 Then Return End If ' Clear the status window. WorkflowStatus.Clear() ' Get the workflow version and display it. ' If the workflow is just starting then this info will not ' be available in the persistence store so do not try and retrieve it. If Not workflowStarting Then Dim instance As WorkflowApplicationInstance = _ WorkflowApplication.GetInstance(WorkflowInstanceId, store) WorkflowVersion.Text = _ WorkflowVersionMap.GetIdentityDescription(instance.DefinitionIdentity) ' Unload the instance. instance.Abandon() End If
if (InstanceId.SelectedIndex == -1) { return; } // Clear the status window. WorkflowStatus.Clear(); // Get the workflow version and display it. // If the workflow is just starting then this info will not // be available in the persistence store so do not try and retrieve it. if (!workflowStarting) { WorkflowApplicationInstance instance = WorkflowApplication.GetInstance(this.WorkflowInstanceId, store); WorkflowVersion.Text = WorkflowVersionMap.GetIdentityDescription(instance.DefinitionIdentity); // Unload the instance. instance.Abandon(); }
Voeg de volgende
ListPersistedWorkflows
methode toe aan de formulierklasse.Private Sub ListPersistedWorkflows() Using localCon As New SqlConnection(connectionString) Dim localCmd As String = _ "SELECT [InstanceId] FROM [System.Activities.DurableInstancing].[Instances] ORDER BY [CreationTime]" Dim cmd As SqlCommand = localCon.CreateCommand() cmd.CommandText = localCmd localCon.Open() Using reader As SqlDataReader = cmd.ExecuteReader(CommandBehavior.CloseConnection) While (reader.Read()) ' Get the InstanceId of the persisted Workflow. Dim id As Guid = Guid.Parse(reader(0).ToString()) InstanceId.Items.Add(id) End While End Using End Using End Sub
using (var localCon = new SqlConnection(connectionString)) { string localCmd = "SELECT [InstanceId] FROM [System.Activities.DurableInstancing].[Instances] ORDER BY [CreationTime]"; 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()); InstanceId.Items.Add(id); } } }
ListPersistedWorkflows
voert een query uit op het exemplaararchief voor persistente werkstroomexemplaren en voegt de exemplaar-id's toe aan decboInstanceId
keuzelijst met invoervak.Voeg de volgende
UpdateStatus
methode en de bijbehorende gemachtigde toe aan de formulierklasse. Met deze methode wordt het statusvenster op het formulier bijgewerkt met de status van de huidige actieve werkstroom.Private Delegate Sub UpdateStatusDelegate(msg As String) Public Sub UpdateStatus(msg As String) ' We may be on a different thread so we need to ' make this call using BeginInvoke. If InvokeRequired Then BeginInvoke(New UpdateStatusDelegate(AddressOf UpdateStatus), msg) Else If Not msg.EndsWith(vbCrLf) Then msg = msg & vbCrLf End If WorkflowStatus.AppendText(msg) ' Ensure that the newly added status is visible. WorkflowStatus.SelectionStart = WorkflowStatus.Text.Length WorkflowStatus.ScrollToCaret() End If End Sub
private delegate void UpdateStatusDelegate(string msg); public void UpdateStatus(string msg) { // We may be on a different thread so we need to // make this call using BeginInvoke. if (InvokeRequired) { BeginInvoke(new UpdateStatusDelegate(UpdateStatus), msg); } else { if (!msg.EndsWith("\r\n")) { msg += "\r\n"; } WorkflowStatus.AppendText(msg); WorkflowStatus.SelectionStart = WorkflowStatus.Text.Length; WorkflowStatus.ScrollToCaret(); } }
Voeg de volgende
GameOver
methode en de bijbehorende gemachtigde toe aan de formulierklasse. Wanneer een werkstroom is voltooid, wordt met deze methode de formuliergebruikersinterface bijgewerkt door de exemplaar-id van de voltooide werkstroom uit de keuzelijst met invoervak InstanceId te verwijderen.Private Delegate Sub GameOverDelegate() Private Sub GameOver() If InvokeRequired Then BeginInvoke(New GameOverDelegate(AddressOf GameOver)) Else ' Remove this instance from the InstanceId combo box. InstanceId.Items.Remove(InstanceId.SelectedItem) InstanceId.SelectedIndex = -1 End If End Sub
private delegate void GameOverDelegate(); private void GameOver() { if (InvokeRequired) { BeginInvoke(new GameOverDelegate(GameOver)); } else { // Remove this instance from the combo box. InstanceId.Items.Remove(InstanceId.SelectedItem); InstanceId.SelectedIndex = -1; } }
Het exemplaararchief, de handlers voor de levenscyclus van werkstromen en extensies configureren
Voeg een
ConfigureWorkflowApplication
methode toe aan de formulierklasse.Private Sub ConfigureWorkflowApplication(wfApp As WorkflowApplication) End Sub
private void ConfigureWorkflowApplication(WorkflowApplication wfApp) { }
Met deze methode configureert u de
WorkflowApplication
gewenste extensies en voegt u handlers toe voor de levenscyclus van de werkstroom.Geef
ConfigureWorkflowApplication
in , geef deSqlWorkflowInstanceStore
voor deWorkflowApplication
.' Configure the persistence store. wfApp.InstanceStore = store
// Configure the persistence store. wfApp.InstanceStore = store;
Maak vervolgens een
StringWriter
exemplaar en voeg deze toe aan deExtensions
verzameling van deWorkflowApplication
. Wanneer eenStringWriter
wordt toegevoegd aan de extensies, worden alleWriteLine
activiteitsuitvoer vastgelegd. Wanneer de werkstroom niet actief wordt, kan deWriteLine
uitvoer worden geëxtraheerd uit hetStringWriter
formulier en worden weergegeven.' Add a StringWriter to the extensions. This captures the output ' from the WriteLine activities so we can display it in the form. Dim sw As New StringWriter() wfApp.Extensions.Add(sw)
// Add a StringWriter to the extensions. This captures the output // from the WriteLine activities so we can display it in the form. var sw = new StringWriter(); wfApp.Extensions.Add(sw);
Voeg de volgende handler toe voor de
Completed
gebeurtenis. Wanneer een werkstroom is voltooid, wordt het aantal beurten om te raden dat het getal wordt weergegeven in het statusvenster. Als de werkstroom wordt beëindigd, wordt de uitzonderingsinformatie die de beëindiging heeft veroorzaakt, weergegeven. Aan het einde van de handler wordt deGameOver
methode aangeroepen, waardoor de voltooide werkstroom uit de lijst met werkstromen wordt verwijderd.wfApp.Completed = _ Sub(e As WorkflowApplicationCompletedEventArgs) If e.CompletionState = ActivityInstanceState.Faulted Then UpdateStatus($"Workflow Terminated. Exception: {e.TerminationException.GetType().FullName}{vbCrLf}{e.TerminationException.Message}") ElseIf e.CompletionState = ActivityInstanceState.Canceled Then UpdateStatus("Workflow Canceled.") Else Dim turns As Integer = Convert.ToInt32(e.Outputs("Turns")) UpdateStatus($"Congratulations, you guessed the number in {turns} turns.") End If GameOver() End Sub
wfApp.Completed = delegate(WorkflowApplicationCompletedEventArgs e) { if (e.CompletionState == ActivityInstanceState.Faulted) { UpdateStatus($"Workflow Terminated. Exception: {e.TerminationException.GetType().FullName}\r\n{e.TerminationException.Message}"); } else if (e.CompletionState == ActivityInstanceState.Canceled) { UpdateStatus("Workflow Canceled."); } else { int turns = Convert.ToInt32(e.Outputs["Turns"]); UpdateStatus($"Congratulations, you guessed the number in {turns} turns."); } GameOver(); };
Voeg het volgende
Aborted
enOnUnhandledException
de handlers toe. DeGameOver
methode wordt niet aangeroepen vanuit deAborted
handler omdat wanneer een werkstroomexemplaren worden afgebroken, deze niet wordt beëindigd en het is mogelijk om het exemplaar op een later tijdstip te hervatten.wfApp.Aborted = _ Sub(e As WorkflowApplicationAbortedEventArgs) UpdateStatus($"Workflow Aborted. Exception: {e.Reason.GetType().FullName}{vbCrLf}{e.Reason.Message}") End Sub wfApp.OnUnhandledException = _ Function(e As WorkflowApplicationUnhandledExceptionEventArgs) UpdateStatus($"Unhandled Exception: {e.UnhandledException.GetType().FullName}{vbCrLf}{e.UnhandledException.Message}") GameOver() Return UnhandledExceptionAction.Terminate End Function
wfApp.Aborted = delegate(WorkflowApplicationAbortedEventArgs e) { UpdateStatus($"Workflow Aborted. Exception: {e.Reason.GetType().FullName}\r\n{e.Reason.Message}"); }; wfApp.OnUnhandledException = delegate(WorkflowApplicationUnhandledExceptionEventArgs e) { UpdateStatus($"Unhandled Exception: {e.UnhandledException.GetType().FullName}\r\n{e.UnhandledException.Message}"); GameOver(); return UnhandledExceptionAction.Terminate; };
Voeg de volgende
PersistableIdle
handler toe. Deze handler haalt deStringWriter
extensie op die is toegevoegd, extraheert de uitvoer van deWriteLine
activiteiten en geeft deze weer in het statusvenster.wfApp.PersistableIdle = _ Function(e As WorkflowApplicationIdleEventArgs) ' Send the current WriteLine outputs to the status window. Dim writers = e.GetInstanceExtensions(Of StringWriter)() For Each writer In writers UpdateStatus(writer.ToString()) Next Return PersistableIdleAction.Unload End Function
wfApp.PersistableIdle = delegate(WorkflowApplicationIdleEventArgs e) { // Send the current WriteLine outputs to the status window. var writers = e.GetInstanceExtensions<StringWriter>(); foreach (var writer in writers) { UpdateStatus(writer.ToString()); } return PersistableIdleAction.Unload; };
De PersistableIdleAction opsomming heeft drie waarden: None, Persisten Unload. Persist zorgt ervoor dat de werkstroom blijft bestaan, maar dat zorgt er niet voor dat de werkstroom wordt uitgeladen. Unload zorgt ervoor dat de werkstroom behouden blijft en wordt uitgeladen.
Het volgende voorbeeld is de voltooide
ConfigureWorkflowApplication
methode.Private Sub ConfigureWorkflowApplication(wfApp As WorkflowApplication) ' Configure the persistence store. wfApp.InstanceStore = store ' Add a StringWriter to the extensions. This captures the output ' from the WriteLine activities so we can display it in the form. Dim sw As New StringWriter() wfApp.Extensions.Add(sw) wfApp.Completed = _ Sub(e As WorkflowApplicationCompletedEventArgs) If e.CompletionState = ActivityInstanceState.Faulted Then UpdateStatus($"Workflow Terminated. Exception: {e.TerminationException.GetType().FullName}{vbCrLf}{e.TerminationException.Message}") ElseIf e.CompletionState = ActivityInstanceState.Canceled Then UpdateStatus("Workflow Canceled.") Else Dim turns As Integer = Convert.ToInt32(e.Outputs("Turns")) UpdateStatus($"Congratulations, you guessed the number in {turns} turns.") End If GameOver() End Sub wfApp.Aborted = _ Sub(e As WorkflowApplicationAbortedEventArgs) UpdateStatus($"Workflow Aborted. Exception: {e.Reason.GetType().FullName}{vbCrLf}{e.Reason.Message}") End Sub wfApp.OnUnhandledException = _ Function(e As WorkflowApplicationUnhandledExceptionEventArgs) UpdateStatus($"Unhandled Exception: {e.UnhandledException.GetType().FullName}{vbCrLf}{e.UnhandledException.Message}") GameOver() Return UnhandledExceptionAction.Terminate End Function wfApp.PersistableIdle = _ Function(e As WorkflowApplicationIdleEventArgs) ' Send the current WriteLine outputs to the status window. Dim writers = e.GetInstanceExtensions(Of StringWriter)() For Each writer In writers UpdateStatus(writer.ToString()) Next Return PersistableIdleAction.Unload End Function End Sub
private void ConfigureWorkflowApplication(WorkflowApplication wfApp) { // Configure the persistence store. wfApp.InstanceStore = store; // Add a StringWriter to the extensions. This captures the output // from the WriteLine activities so we can display it in the form. var sw = new StringWriter(); wfApp.Extensions.Add(sw); wfApp.Completed = delegate(WorkflowApplicationCompletedEventArgs e) { if (e.CompletionState == ActivityInstanceState.Faulted) { UpdateStatus($"Workflow Terminated. Exception: {e.TerminationException.GetType().FullName}\r\n{e.TerminationException.Message}"); } else if (e.CompletionState == ActivityInstanceState.Canceled) { UpdateStatus("Workflow Canceled."); } else { int turns = Convert.ToInt32(e.Outputs["Turns"]); UpdateStatus($"Congratulations, you guessed the number in {turns} turns."); } GameOver(); }; wfApp.Aborted = delegate(WorkflowApplicationAbortedEventArgs e) { UpdateStatus($"Workflow Aborted. Exception: {e.Reason.GetType().FullName}\r\n{e.Reason.Message}"); }; wfApp.OnUnhandledException = delegate(WorkflowApplicationUnhandledExceptionEventArgs e) { UpdateStatus($"Unhandled Exception: {e.UnhandledException.GetType().FullName}\r\n{e.UnhandledException.Message}"); GameOver(); return UnhandledExceptionAction.Terminate; }; wfApp.PersistableIdle = delegate(WorkflowApplicationIdleEventArgs e) { // Send the current WriteLine outputs to the status window. var writers = e.GetInstanceExtensions<StringWriter>(); foreach (var writer in writers) { UpdateStatus(writer.ToString()); } return PersistableIdleAction.Unload; }; }
Starten en hervatten van meerdere werkstroomtypen inschakelen
Als u een werkstroomexemplaren wilt hervatten, moet de host de werkstroomdefinitie opgeven. In deze zelfstudie zijn er drie werkstroomtypen en in de volgende zelfstudiestappen worden meerdere versies van deze typen geïntroduceerd. WorkflowIdentity
biedt een manier voor een hosttoepassing om identificatiegegevens te koppelen aan een persistent werkstroomexemplaren. De stappen in deze sectie laten zien hoe u een hulpprogrammaklasse maakt om u te helpen bij het toewijzen van de werkstroomidentiteit van een persistent werkstroomexemplaren aan de bijbehorende werkstroomdefinitie. Zie WorkflowIdentity en Versiebeheer gebruiken voor meer informatie over WorkflowIdentity
en versiebeheer.
Klik met de rechtermuisknop op NumberGuessWorkflowHost in Solution Explorer en kies Toevoegen, Klasse. Typ
WorkflowVersionMap
in het vak Naam en klik op Toevoegen.Voeg de volgende
using
ofImports
instructies toe bovenaan het bestand met de andereusing
ofImports
instructies.Imports System.Activities Imports NumberGuessWorkflowActivities
using System.Activities; using NumberGuessWorkflowActivities;
Vervang de
WorkflowVersionMap
klassedeclaratie door de volgende declaratie.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 Sub New() map = New Dictionary(Of WorkflowIdentity, Activity) ' Add the current workflow version identities. StateMachineNumberGuessIdentity = New WorkflowIdentity With { .Name = "StateMachineNumberGuessWorkflow", .Version = New Version(1, 0, 0, 0) } FlowchartNumberGuessIdentity = New WorkflowIdentity With { .Name = "FlowchartNumberGuessWorkflow", .Version = New Version(1, 0, 0, 0) } SequentialNumberGuessIdentity = New WorkflowIdentity With { .Name = "SequentialNumberGuessWorkflow", .Version = New Version(1, 0, 0, 0) } map.Add(StateMachineNumberGuessIdentity, New StateMachineNumberGuessWorkflow()) map.Add(FlowchartNumberGuessIdentity, New FlowchartNumberGuessWorkflow()) map.Add(SequentialNumberGuessIdentity, New SequentialNumberGuessWorkflow()) 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; 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) }; FlowchartNumberGuessIdentity = new WorkflowIdentity { Name = "FlowchartNumberGuessWorkflow", Version = new Version(1, 0, 0, 0) }; SequentialNumberGuessIdentity = new WorkflowIdentity { Name = "SequentialNumberGuessWorkflow", Version = new Version(1, 0, 0, 0) }; map.Add(StateMachineNumberGuessIdentity, new StateMachineNumberGuessWorkflow()); map.Add(FlowchartNumberGuessIdentity, new FlowchartNumberGuessWorkflow()); map.Add(SequentialNumberGuessIdentity, new SequentialNumberGuessWorkflow()); } public static Activity GetWorkflowDefinition(WorkflowIdentity identity) { return map[identity]; } public static string GetIdentityDescription(WorkflowIdentity identity) { return identity.ToString(); } }
WorkflowVersionMap
bevat drie werkstroomidentiteiten die zijn toegewezen aan de drie werkstroomdefinities uit deze zelfstudie en worden gebruikt in de volgende secties wanneer werkstromen worden gestart en hervat.
Een nieuwe werkstroom starten
Voeg een
Click
handler toe voorNewGame
. Als u de handler wilt toevoegen, schakelt u over naar de ontwerpweergave voor het formulier en dubbelklikt u eropNewGame
. Er wordt eenNewGame_Click
handler toegevoegd en de weergave schakelt over naar de codeweergave voor het formulier. Wanneer de gebruiker op deze knop klikt, wordt er een nieuwe werkstroom gestart.Private Sub NewGame_Click(sender As Object, e As EventArgs) Handles NewGame.Click End Sub
private void NewGame_Click(object sender, EventArgs e) { }
Voeg de volgende code toe aan de klikhandler. Met deze code maakt u een woordenlijst met invoerargumenten voor de werkstroom, gesleuteld op argumentnaam. Deze woordenlijst bevat één vermelding die het bereik bevat van het willekeurig gegenereerde getal dat is opgehaald uit de keuzelijst met invoervak voor het bereik.
Dim inputs As New Dictionary(Of String, Object)() inputs.Add("MaxNumber", Convert.ToInt32(NumberRange.SelectedItem))
var inputs = new Dictionary<string, object>(); inputs.Add("MaxNumber", Convert.ToInt32(NumberRange.SelectedItem));
Voeg vervolgens de volgende code toe waarmee de werkstroom wordt gestart. De
WorkflowIdentity
definitie van de werkstroom en de werkstroom die overeenkomt met het type werkstroom dat is geselecteerd, worden opgehaald met behulp van deWorkflowVersionMap
helperklasse. Vervolgens wordt een nieuwWorkflowApplication
exemplaar gemaakt met behulp van de werkstroomdefinitieWorkflowIdentity
en de woordenlijst met invoerargumenten.Dim identity As WorkflowIdentity = Nothing Select Case WorkflowType.SelectedItem.ToString() Case "SequentialNumberGuessWorkflow" identity = WorkflowVersionMap.SequentialNumberGuessIdentity Case "StateMachineNumberGuessWorkflow" identity = WorkflowVersionMap.StateMachineNumberGuessIdentity Case "FlowchartNumberGuessWorkflow" identity = WorkflowVersionMap.FlowchartNumberGuessIdentity End Select Dim wf As Activity = WorkflowVersionMap.GetWorkflowDefinition(identity) Dim wfApp = New WorkflowApplication(wf, inputs, identity)
WorkflowIdentity identity = null; switch (WorkflowType.SelectedItem.ToString()) { case "SequentialNumberGuessWorkflow": identity = WorkflowVersionMap.SequentialNumberGuessIdentity; break; case "StateMachineNumberGuessWorkflow": identity = WorkflowVersionMap.StateMachineNumberGuessIdentity; break; case "FlowchartNumberGuessWorkflow": identity = WorkflowVersionMap.FlowchartNumberGuessIdentity; break; }; Activity wf = WorkflowVersionMap.GetWorkflowDefinition(identity); WorkflowApplication wfApp = new WorkflowApplication(wf, inputs, identity);
Voeg vervolgens de volgende code toe waarmee de werkstroom wordt toegevoegd aan de lijst met werkstromen en de versiegegevens van de werkstroom op het formulier worden weergegeven.
' Add the workflow to the list and display the version information. workflowStarting = True InstanceId.SelectedIndex = InstanceId.Items.Add(wfApp.Id) WorkflowVersion.Text = identity.ToString() workflowStarting = False
// Add the workflow to the list and display the version information. workflowStarting = true; InstanceId.SelectedIndex = InstanceId.Items.Add(wfApp.Id); WorkflowVersion.Text = identity.ToString(); workflowStarting = false;
Aanroep
ConfigureWorkflowApplication
voor het configureren van het exemplaararchief, extensies en werkstroomlevenscyclushandlers voor ditWorkflowApplication
exemplaar.' Configure the instance store, extensions, and ' workflow lifecycle handlers. ConfigureWorkflowApplication(wfApp)
// Configure the instance store, extensions, and // workflow lifecycle handlers. ConfigureWorkflowApplication(wfApp);
Bel ten slotte
Run
.' Start the workflow. wfApp.Run()
// Start the workflow. wfApp.Run();
Het volgende voorbeeld is de voltooide
NewGame_Click
handler.Private Sub NewGame_Click(sender As Object, e As EventArgs) Handles NewGame.Click ' Start a new workflow. Dim inputs As New Dictionary(Of String, Object)() inputs.Add("MaxNumber", Convert.ToInt32(NumberRange.SelectedItem)) Dim identity As WorkflowIdentity = Nothing Select Case WorkflowType.SelectedItem.ToString() Case "SequentialNumberGuessWorkflow" identity = WorkflowVersionMap.SequentialNumberGuessIdentity Case "StateMachineNumberGuessWorkflow" identity = WorkflowVersionMap.StateMachineNumberGuessIdentity Case "FlowchartNumberGuessWorkflow" identity = WorkflowVersionMap.FlowchartNumberGuessIdentity End Select Dim wf As Activity = WorkflowVersionMap.GetWorkflowDefinition(identity) Dim wfApp = New WorkflowApplication(wf, inputs, identity) ' Add the workflow to the list and display the version information. workflowStarting = True InstanceId.SelectedIndex = InstanceId.Items.Add(wfApp.Id) WorkflowVersion.Text = identity.ToString() workflowStarting = False ' Configure the instance store, extensions, and ' workflow lifecycle handlers. ConfigureWorkflowApplication(wfApp) ' Start the workflow. wfApp.Run() End Sub
private void NewGame_Click(object sender, EventArgs e) { var inputs = new Dictionary<string, object>(); inputs.Add("MaxNumber", Convert.ToInt32(NumberRange.SelectedItem)); WorkflowIdentity identity = null; switch (WorkflowType.SelectedItem.ToString()) { case "SequentialNumberGuessWorkflow": identity = WorkflowVersionMap.SequentialNumberGuessIdentity; break; case "StateMachineNumberGuessWorkflow": identity = WorkflowVersionMap.StateMachineNumberGuessIdentity; break; case "FlowchartNumberGuessWorkflow": identity = WorkflowVersionMap.FlowchartNumberGuessIdentity; break; }; Activity wf = WorkflowVersionMap.GetWorkflowDefinition(identity); var wfApp = new WorkflowApplication(wf, inputs, identity); // Add the workflow to the list and display the version information. workflowStarting = true; InstanceId.SelectedIndex = InstanceId.Items.Add(wfApp.Id); WorkflowVersion.Text = identity.ToString(); workflowStarting = false; // Configure the instance store, extensions, and // workflow lifecycle handlers. ConfigureWorkflowApplication(wfApp); // Start the workflow. wfApp.Run(); }
Een werkstroom hervatten
Voeg een
Click
handler toe voorEnterGuess
. Als u de handler wilt toevoegen, schakelt u over naar de ontwerpweergave voor het formulier en dubbelklikt u eropEnterGuess
. Wanneer de gebruiker op deze knop klikt, wordt een werkstroom hervat.Private Sub EnterGuess_Click(sender As Object, e As EventArgs) Handles EnterGuess.Click End Sub
private void EnterGuess_Click(object sender, EventArgs e) { }
Voeg de volgende code toe om ervoor te zorgen dat een werkstroom is geselecteerd in de lijst met werkstromen en of de schatting van de gebruiker geldig is.
If WorkflowInstanceId = Guid.Empty Then MessageBox.Show("Please select a workflow.") Return End If Dim userGuess As Integer If Not Int32.TryParse(Guess.Text, userGuess) Then MessageBox.Show("Please enter an integer.") Guess.SelectAll() Guess.Focus() Return End If
if (WorkflowInstanceId == Guid.Empty) { MessageBox.Show("Please select a workflow."); return; } int guess; if (!Int32.TryParse(Guess.Text, out guess)) { MessageBox.Show("Please enter an integer."); Guess.SelectAll(); Guess.Focus(); return; }
Haal vervolgens het
WorkflowApplicationInstance
persistente werkstroomexemplaren op. AWorkflowApplicationInstance
vertegenwoordigt een persistent werkstroomexemplaar dat nog niet is gekoppeld aan een werkstroomdefinitie. DeDefinitionIdentity
van deWorkflowApplicationInstance
bevat deWorkflowIdentity
persistente werkstroominstantie. In deze zelfstudie wordt deWorkflowVersionMap
hulpprogrammaklasse gebruikt om deWorkflowIdentity
juiste werkstroomdefinitie toe te wijzen. Zodra de werkstroomdefinitie is opgehaald, wordt er eenWorkflowApplication
gemaakt met behulp van de juiste werkstroomdefinitie.Dim instance As WorkflowApplicationInstance = _ WorkflowApplication.GetInstance(WorkflowInstanceId, store) ' Use the persisted WorkflowIdentity to retrieve the correct workflow ' definition from the dictionary. Dim wf As Activity = _ WorkflowVersionMap.GetWorkflowDefinition(instance.DefinitionIdentity) ' Associate the WorkflowApplication with the correct definition Dim wfApp As New WorkflowApplication(wf, instance.DefinitionIdentity)
WorkflowApplicationInstance instance = WorkflowApplication.GetInstance(WorkflowInstanceId, store); // Use the persisted WorkflowIdentity to retrieve the correct workflow // definition from the dictionary. Activity wf = WorkflowVersionMap.GetWorkflowDefinition(instance.DefinitionIdentity); // Associate the WorkflowApplication with the correct definition var wfApp = new WorkflowApplication(wf, instance.DefinitionIdentity);
Zodra de app
WorkflowApplication
is gemaakt, configureert u het exemplaararchief, de werkstroomlevenscyclushandlers en -extensies door aan te roepenConfigureWorkflowApplication
. Deze stappen moeten worden uitgevoerd telkens wanneer er een nieuweWorkflowApplication
wordt gemaakt en moeten worden uitgevoerd voordat het werkstroomexemplaren in hetWorkflowApplication
werkstroomexemplaren worden geladen. Nadat de werkstroom is geladen, wordt deze hervat met de schatting van de gebruiker.' Configure the extensions and lifecycle handlers. ' Do this before the instance is loaded. Once the instance is ' loaded it is too late to add extensions. ConfigureWorkflowApplication(wfApp) ' Load the workflow. wfApp.Load(instance) ' Resume the workflow. wfApp.ResumeBookmark("EnterGuess", userGuess)
// Configure the extensions and lifecycle handlers. // Do this before the instance is loaded. Once the instance is // loaded it is too late to add extensions. ConfigureWorkflowApplication(wfApp); // Load the workflow. wfApp.Load(instance); // Resume the workflow. wfApp.ResumeBookmark("EnterGuess", guess);
Ten slotte wist u het tekstvak voor schattingen en bereidt u het formulier voor om een andere schatting te accepteren.
' Clear the Guess textbox. Guess.Clear() Guess.Focus()
// Clear the Guess textbox. Guess.Clear(); Guess.Focus();
Het volgende voorbeeld is de voltooide
EnterGuess_Click
handler.Private Sub EnterGuess_Click(sender As Object, e As EventArgs) Handles EnterGuess.Click If WorkflowInstanceId = Guid.Empty Then MessageBox.Show("Please select a workflow.") Return End If Dim userGuess As Integer If Not Int32.TryParse(Guess.Text, userGuess) Then MessageBox.Show("Please enter an integer.") Guess.SelectAll() Guess.Focus() Return End If Dim instance As WorkflowApplicationInstance = _ WorkflowApplication.GetInstance(WorkflowInstanceId, store) ' Use the persisted WorkflowIdentity to retrieve the correct workflow ' definition from the dictionary. Dim wf As Activity = _ WorkflowVersionMap.GetWorkflowDefinition(instance.DefinitionIdentity) ' Associate the WorkflowApplication with the correct definition Dim wfApp As New WorkflowApplication(wf, instance.DefinitionIdentity) ' Configure the extensions and lifecycle handlers. ' Do this before the instance is loaded. Once the instance is ' loaded it is too late to add extensions. ConfigureWorkflowApplication(wfApp) ' Load the workflow. wfApp.Load(instance) ' Resume the workflow. wfApp.ResumeBookmark("EnterGuess", userGuess) ' Clear the Guess textbox. Guess.Clear() Guess.Focus() End Sub
private void EnterGuess_Click(object sender, EventArgs e) { if (WorkflowInstanceId == Guid.Empty) { MessageBox.Show("Please select a workflow."); return; } int guess; if (!Int32.TryParse(Guess.Text, out guess)) { MessageBox.Show("Please enter an integer."); Guess.SelectAll(); Guess.Focus(); return; } WorkflowApplicationInstance instance = WorkflowApplication.GetInstance(WorkflowInstanceId, store); // Use the persisted WorkflowIdentity to retrieve the correct workflow // definition from the dictionary. Activity wf = WorkflowVersionMap.GetWorkflowDefinition(instance.DefinitionIdentity); // Associate the WorkflowApplication with the correct definition var wfApp = new WorkflowApplication(wf, instance.DefinitionIdentity); // Configure the extensions and lifecycle handlers. // Do this before the instance is loaded. Once the instance is // loaded it is too late to add extensions. ConfigureWorkflowApplication(wfApp); // Load the workflow. wfApp.Load(instance); // Resume the workflow. wfApp.ResumeBookmark("EnterGuess", guess); // Clear the Guess textbox. Guess.Clear(); Guess.Focus(); }
Een werkstroom beëindigen
Voeg een
Click
handler toe voorQuitGame
. Als u de handler wilt toevoegen, schakelt u over naar de ontwerpweergave voor het formulier en dubbelklikt u eropQuitGame
. Wanneer de gebruiker op deze knop klikt, wordt de geselecteerde werkstroom beëindigd.Private Sub QuitGame_Click(sender As Object, e As EventArgs) Handles QuitGame.Click End Sub
private void QuitGame_Click(object sender, EventArgs e) { }
Voeg de volgende code toe aan de
QuitGame_Click
handler. Met deze code wordt eerst gecontroleerd of een werkstroom is geselecteerd in de lijst met werkstromen. Vervolgens wordt het persistente exemplaar in eenWorkflowApplicationInstance
geladen, wordt de instantie gebruiktDefinitionIdentity
om de juiste werkstroomdefinitie te bepalen en initialiseert u vervolgens deWorkflowApplication
. Vervolgens worden de uitbreidingen en werkstroomlevenscyclushandlers geconfigureerd met een aanroep naarConfigureWorkflowApplication
. Zodra deWorkflowApplication
configuratie is geconfigureerd, wordt deze geladen en vervolgensTerminate
aangeroepen.If WorkflowInstanceId = Guid.Empty Then MessageBox.Show("Please select a workflow.") Return End If Dim instance As WorkflowApplicationInstance = _ WorkflowApplication.GetInstance(WorkflowInstanceId, store) ' Use the persisted WorkflowIdentity to retrieve the correct workflow ' definition from the dictionary. Dim wf As Activity = WorkflowVersionMap.GetWorkflowDefinition(instance.DefinitionIdentity) ' Associate the WorkflowApplication with the correct definition. Dim wfApp As New WorkflowApplication(wf, instance.DefinitionIdentity) ' Configure the extensions and lifecycle handlers. ConfigureWorkflowApplication(wfApp) ' Load the workflow. wfApp.Load(instance) ' Terminate the workflow. wfApp.Terminate("User resigns.")
if (WorkflowInstanceId == Guid.Empty) { MessageBox.Show("Please select a workflow."); return; } WorkflowApplicationInstance instance = WorkflowApplication.GetInstance(WorkflowInstanceId, store); // Use the persisted WorkflowIdentity to retrieve the correct workflow // definition from the dictionary. Activity wf = WorkflowVersionMap.GetWorkflowDefinition(instance.DefinitionIdentity); // Associate the WorkflowApplication with the correct definition var wfApp = new WorkflowApplication(wf, instance.DefinitionIdentity); // Configure the extensions and lifecycle handlers ConfigureWorkflowApplication(wfApp); // Load the workflow. wfApp.Load(instance); // Terminate the workflow. wfApp.Terminate("User resigns.");
De toepassing bouwen en uitvoeren
Dubbelklik op Program.cs (of Module1.vb) in Solution Explorer om de code weer te geven.
Voeg de volgende
using
(ofImports
) instructie toe boven aan het bestand met de andereusing
(ofImports
) instructies.Imports System.Windows.Forms
using System.Windows.Forms;
Verwijder of markeer de bestaande werkstroomhostingcode uit Procedure: Voer een werkstroom uit en vervang deze door de volgende code.
Sub Main() Application.EnableVisualStyles() Application.Run(New WorkflowHostForm()) End Sub
static void Main(string[] args) { Application.EnableVisualStyles(); Application.Run(new WorkflowHostForm()); }
Klik met de rechtermuisknop op NumberGuessWorkflowHost in Solution Explorer en kies Eigenschappen. Geef op het tabblad Toepassing Windows-toepassing op voor het uitvoertype. Deze stap is optioneel, maar als het consolevenster niet wordt gevolgd, wordt naast het formulier weergegeven.
Druk op Ctrl+Shift+B om de toepassing te bouwen.
Zorg ervoor dat NumberGuessWorkflowHost is ingesteld als de opstarttoepassing en druk op Ctrl+F5 om de toepassing te starten.
Selecteer een bereik voor het gokspel en het type werkstroom dat u wilt starten en klik op Nieuw spel. Voer een schatting in het vak Schatting in en klik op Ga om uw schatting in te dienen. De uitvoer van de
WriteLine
activiteiten wordt weergegeven in het formulier.Start verschillende werkstromen met verschillende werkstroomtypen en numerieke bereiken, voer enkele schattingen in en schakel tussen de werkstromen door een selectie te maken in de lijst Met werkstroomexemplaren .
Wanneer u overschakelt naar een nieuwe werkstroom, worden de vorige schattingen en voortgang van de werkstroom niet weergegeven in het statusvenster. De reden waarom de status niet beschikbaar is, is omdat deze nergens wordt vastgelegd en opgeslagen. In de volgende stap van de zelfstudie, Procedure: Een aangepaste deelnemer voor bijhouden maken, maakt u een aangepaste traceringsdeelnemer die deze informatie opslaat.