Vorgehensweise: Ausführen eines Workflows
Dieses Thema ist eine Fortsetzung des Tutorials „Windows Workflow Foundation: Erste Schritte“. Hierin wird beschrieben, wie Sie einen Workflowhost erstellen und den im vorherigen Thema How to: Create a Workflow definierten Workflow ausführen.
Hinweis
Ein Thema im Lernprogramm "Erste Schritte" hängt jeweils von den vorherigen Themen ab. Um dieses Thema verwenden zu können, müssen Sie zuerst How to: Create an Activity und How to: Create a Workflowdurcharbeiten und abschließen.
So erstellen Sie das Workflowhostprojekt
Öffnen Sie die Projektmappe des vorherigen Themas Vorgehensweise: Erstellen einer Aktivität mit Visual Studio 2012 durcharbeiten und abschließen.
Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf WF45GettingStartedTutorial , zeigen Sie auf Hinzufügen, und wählen Sie Neues Projektaus.
Tipp
Wird das Fenster Projektmappen-Explorer nicht angezeigt, wählen Sie Projektmappen-Explorer im Menü Ansicht aus.
Wählen Sie im Knoten Installiert die Option Visual C#und anschließend Workflow (oder Visual Basic, Workflow) aus.
Hinweis
Abhängig davon, welche Programmiersprache als primäre Sprache in Visual Studio konfiguriert ist, kann sich der Knoten Visual C# oder Visual Basic unter dem Knoten Andere Sprachen im Knoten Installiert befinden.
Stellen Sie sicher, dass .NET Framework 4.5 in der Dropdownliste für die .NET Framework-Version ausgewählt ist. Wählen Sie in der Liste Workflow die Option Konsolenanwendung für Workflows aus. Geben Sie im Feld
NumberGuessWorkflowHost
Name die Bezeichnung ein, und klicken Sie auf OK. Auf diese Weise wird eine Start-Workflowanwendung mit grundlegender Unterstützung von Workflowhosting erstellt. Dieser grundlegende Hostingcode wird geändert und zum Ausführen der Workflowanwendung verwendet.Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf das neu hinzugefügte Projekt NumberGuessWorkflowHost , und wählen Sie Verweis hinzufügenaus. Wählen Sie in der Liste Verweis hinzufügen den Eintrag Projektmappe aus, aktivieren Sie das Kontrollkästchen neben NumberGuessWorkflowActivities, und klicken Sie auf OK.
Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf Workflow1.xaml , und wählen Sie Löschenaus. Klicken Sie auf OK , um zu bestätigen.
So ändern Sie den Code zum Hosten von Workflows
Doppelklicken Sie im Projektmappen-Explorer auf Program.cs oder Module1.vb , um den Code anzuzeigen.
Tipp
Wird das Fenster Projektmappen-Explorer nicht angezeigt, wählen Sie Projektmappen-Explorer im Menü Ansicht aus.
Da dieses Projekt mit der Vorlage Konsolenanwendung für Workflows erstellt wurde, enthält Program.cs oder Module1.vb den folgenden grundlegenden Code zum Hosten von Workflows.
' Create and cache the workflow definition. Dim workflow1 As Activity = New Workflow1() WorkflowInvoker.Invoke(workflow1)
// Create and cache the workflow definition. Activity workflow1 = new Workflow1(); WorkflowInvoker.Invoke(workflow1);
Der generierte Hostingcode verwendet WorkflowInvoker. WorkflowInvoker stellt eine einfache Möglichkeit zum Aufrufen eines Workflows bereit, so als handelte es sich um einen Methodenaufruf, und kann nur für Workflows verwendet werden, die keine Persistenz verwenden. WorkflowApplication bietet ein umfangreicheres Modell zum Ausführen von Workflows, die Benachrichtigungen über Lebenszyklusereignisse, Ausführungssteuerung, Wiederaufnahme von Lesezeichen und Persistenz enthalten. In diesem Beispiel werden Lesezeichen verwendet, und WorkflowApplication wird zum Hosten des Workflows genutzt. Fügen Sie die folgende
using
- oder Imports -Anweisung am Anfang von Program.cs oder Module1.vb unter der vorhandenen using - oder Imports -Anweisung hinzu.Imports NumberGuessWorkflowActivities Imports System.Threading
using NumberGuessWorkflowActivities; using System.Threading;
Ersetzen Sie die Codezeilen, in denen WorkflowInvoker mit dem folgenden grundlegenden WorkflowApplication -Hostingcode verwendet wird. In diesem Beispielhostingcode werden die grundlegenden Schritte zum Hosten und das Aufrufen eines Workflows veranschaulicht, das Beispiel enthält jedoch noch nicht die Funktionalität zum erfolgreichen Ausführen des Workflows aus diesem Thema. In den folgenden Schritten wird der grundlegende Code geändert, und es werden zusätzliche Funktionen hinzugefügt, bis die Anwendung abgeschlossen wurde.
Hinweis
Sie müssen
Workflow1
in diesen Beispielen durchFlowchartNumberGuessWorkflow
,SequentialNumberGuessWorkflow
oderStateMachineNumberGuessWorkflow
ersetzen, je nachdem, welchen Workflow Sie im vorherigen Schritt How to: Create a Workflow abgeschlossen haben. Wenn SieWorkflow1
nicht ersetzen, erhalten Sie Buildfehler, wenn Sie versuchen, den Workflow zu erstellen oder auszuführen.AutoResetEvent syncEvent = new AutoResetEvent(false); WorkflowApplication wfApp = new WorkflowApplication(_wf); wfApp.Completed = delegate (WorkflowApplicationCompletedEventArgs e) { syncEvent.Set(); }; wfApp.Aborted = delegate (WorkflowApplicationAbortedEventArgs e) { Console.WriteLine(e.Reason); syncEvent.Set(); }; wfApp.OnUnhandledException = delegate (WorkflowApplicationUnhandledExceptionEventArgs e) { Console.WriteLine(e.UnhandledException.ToString()); return UnhandledExceptionAction.Terminate; }; wfApp.Run(); syncEvent.WaitOne();
Dim syncEvent As New AutoResetEvent(False) Dim wfApp As New WorkflowApplication(New Workflow1()) wfApp.Completed = Sub(e As WorkflowApplicationCompletedEventArgs) syncEvent.Set() End Sub wfApp.Aborted = Sub(e As WorkflowApplicationAbortedEventArgs) Console.WriteLine(e.Reason) syncEvent.Set() End Sub wfApp.OnUnhandledException = Function(e As WorkflowApplicationUnhandledExceptionEventArgs) Console.WriteLine(e.UnhandledException) Return UnhandledExceptionAction.Terminate End Function wfApp.Run() syncEvent.WaitOne()
In diesem Code wird ein WorkflowApplication-Element erstellt, es werden drei Lebenszyklusereignisse des Workflows abonniert, der Workflow wird per Aufruf von Rungestartet, und dann wird auf den Abschluss des Workflows gewartet. Nach Abschluss des Workflows wird AutoResetEvent festgelegt, und die Hostanwendung wird abgeschlossen.
So legen Sie die Eingabeargumente eines Workflows fest
Fügen Sie oben in der Datei Program.cs oder Module1.vb unter den vorhandenen
using
- oderImports
-Anweisung die folgende Anweisung hinzu.Ersetzen Sie die Codezeile, die das neue WorkflowApplication -Element erstellt, durch den folgenden Code, der ein Wörterbuch mit Parametern erstellt und dieses nach seiner Erstellung an den Workflow übergibt.
Hinweis
Ersetzen Sie
Workflow1
in diesen Beispielen durchFlowchartNumberGuessWorkflow
, und wählen SieSequentialNumberGuessWorkflow
, und wählen Sie orStateMachineNumberGuessWorkflow
, und wählen Sie depending on which workflow you completed in the previous How to: Create a Workflow abgeschlossen haben. Wenn SieWorkflow1
nicht ersetzen, erhalten Sie Buildfehler, wenn Sie versuchen, den Workflow zu erstellen oder auszuführen.var inputs = new Dictionary<string, object>() { { "MaxNumber", 100 } }; WorkflowApplication wfApp = new(_wf, inputs) {
Dim inputs As New Dictionary(Of String, Object) inputs.Add("MaxNumber", 100) Dim wfApp As New WorkflowApplication(New Workflow1(), inputs)
Dieses Wörterbuch enthält ein Element mit dem Schlüssel
MaxNumber
. Schlüssel im Eingabewörterbuch entsprechen Eingabeargumenten in der Stammaktivität des Workflows.MaxNumber
wird vom Workflow verwendet, um die Obergrenze für die zufällig generierte Zahl zu bestimmen.
So rufen Sie die Ausgabeargumente eines Workflows ab
Ändern Sie den Completed -Handler, um die Anzahl der vom Workflow verwendeten Durchgänge (turns) abzurufen und anzuzeigen.
Completed = delegate (WorkflowApplicationCompletedEventArgs e) { int Turns = Convert.ToInt32(e.Outputs["Turns"]); Console.WriteLine("Congratulations, you guessed the number in {0} turns.", Turns); syncEvent.Set(); },
wfApp.Completed = Sub(e As WorkflowApplicationCompletedEventArgs) Dim Turns As Integer = Convert.ToInt32(e.Outputs("Turns")) Console.WriteLine("Congratulations, you guessed the number in {0} turns.", Turns) syncEvent.Set() End Sub
So nehmen Sie ein Lesezeichen wieder auf
Fügen Sie oben in der
Main
-Methode direkt nach der bestehenden AutoResetEvent -Deklaration den folgenden Code hinzu.AutoResetEvent idleEvent = new AutoResetEvent(false);
Dim idleEvent As New AutoResetEvent(False)
Fügen Sie direkt unterhalb der drei bestehenden Lebenszyklushandler des Workflows im Abschnitt Idle den folgenden
Main
-Handler hinzu.Idle = delegate (WorkflowApplicationIdleEventArgs e) { idleEvent.Set(); } };
wfApp.Idle = Sub(e As WorkflowApplicationIdleEventArgs) idleEvent.Set() End Sub
Immer, wenn der Workflow dann in den Leerlaufzustand eintritt und auf den nächsten Lösungsversuch wartet, wird dieser Handler aufgerufen und
idleAction
AutoResetEvent festgelegt. Der Code im folgenden Schritt verwendetidleEvent
undsyncEvent
, um zu ermitteln, ob der Workflow auf den nächsten Lösungsversuch wartet oder abgeschlossen ist.Hinweis
In diesem Beispiel verwendet die Hostanwendung AutoReset-Ereignisse in den Handlern Completed und Idle , um die Hostanwendung mit dem Status des Workflows zu synchronisieren. Das Blockieren und das Warten auf den Eintritt des Workflows in den Leerlaufzustand ist nicht erforderlich, bevor ein Lesezeichen wiederaufgenommen wird. In diesem Beispiel sind die Synchronisierungsereignisse jedoch erforderlich, damit der Host weiß, ob der Workflow abgeschlossen ist oder ob dieser mithilfe von Bookmarkauf weitere Benutzereingaben wartet. Weitere Informationen finden Sie unter Textmarken.
Entfernen Sie den Aufruf von
WaitOne
, und ersetzen Sie diesen durch Code zum Erfassen der Eingabe des Benutzers und zum Wiederaufnehmen von Bookmark.Entfernen Sie die folgende Codezeile.
syncEvent.WaitOne();
syncEvent.WaitOne()
Ersetzen Sie diese durch den folgenden Beispielcode.
// Loop until the workflow completes. WaitHandle[] handles = new WaitHandle[] { syncEvent, idleEvent }; while (WaitHandle.WaitAny(handles) != 0) { // Gather the user input and resume the bookmark. bool validEntry = false; while (!validEntry) { if (!Int32.TryParse(Console.ReadLine(), out int Guess)) { Console.WriteLine("Please enter an integer."); } else { validEntry = true; wfApp.ResumeBookmark("EnterGuess", Guess); } } }
' Loop until the workflow completes. Dim waitHandles As WaitHandle() = New WaitHandle() {syncEvent, idleEvent} Do While WaitHandle.WaitAny(waitHandles) <> 0 'Gather the user input and resume the bookmark. Dim validEntry As Boolean = False Do While validEntry = False Dim Guess As Integer If Int32.TryParse(Console.ReadLine(), Guess) = False Then Console.WriteLine("Please enter an integer.") Else validEntry = True wfApp.ResumeBookmark("EnterGuess", Guess) End If Loop Loop
So erstellen Sie die Anwendung und führen sie aus
Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf NumberGuessWorkflowHost , und wählen Sie Als Startprojekt festlegenaus.
Drücken Sie STRG+F5, um die Anwendung zu erstellen und auszuführen. Versuchen Sie, die Zahl in möglichst wenigen Durchgängen zu erraten.
Um die Anwendung mit einem der anderen Workflowtypen auszuprobieren, ersetzen Sie
Workflow1
im Code, durch den WorkflowApplication erstellt wird, durchFlowchartNumberGuessWorkflow
,SequentialNumberGuessWorkflow
oderStateMachineNumberGuessWorkflow
, je nachdem, welcher Workflowtyp gewünscht ist.var inputs = new Dictionary<string, object>() { { "MaxNumber", 100 } }; WorkflowApplication wfApp = new(_wf, inputs) {
Dim inputs As New Dictionary(Of String, Object) inputs.Add("MaxNumber", 100) Dim wfApp As New WorkflowApplication(New Workflow1(), inputs)
Eine Anleitung dazu, wie Sie einer Workflowanwendung Persistenz hinzufügen, finden Sie im nächsten Thema: How to: Create and Run a Long Running Workflow.
Beispiel
Das folgende Beispiel ist die vollständige Codeauflistung für die Main
-Methode.
Hinweis
Ersetzen Sie Workflow1
in diesen Beispielen durch FlowchartNumberGuessWorkflow
, und wählen Sie SequentialNumberGuessWorkflow
, und wählen Sie or StateMachineNumberGuessWorkflow
, und wählen Sie depending on which workflow you completed in the previous How to: Create a Workflow abgeschlossen haben. Wenn Sie Workflow1
nicht ersetzen, erhalten Sie Buildfehler, wenn Sie versuchen, den Workflow zu erstellen oder auszuführen.
static void Main(string[] args)
{
AutoResetEvent syncEvent = new AutoResetEvent(false);
AutoResetEvent idleEvent = new AutoResetEvent(false);
var inputs = new Dictionary<string, object>() { { "MaxNumber", 100 } };
WorkflowApplication wfApp = new(_wf, inputs)
{
Completed = delegate (WorkflowApplicationCompletedEventArgs e)
{
int Turns = Convert.ToInt32(e.Outputs["Turns"]);
Console.WriteLine("Congratulations, you guessed the number in {0} turns.", Turns);
syncEvent.Set();
},
Aborted = delegate (WorkflowApplicationAbortedEventArgs e)
{
Console.WriteLine(e.Reason);
syncEvent.Set();
},
OnUnhandledException = delegate (WorkflowApplicationUnhandledExceptionEventArgs e)
{
Console.WriteLine(e.UnhandledException.ToString());
return UnhandledExceptionAction.Terminate;
},
Idle = delegate (WorkflowApplicationIdleEventArgs e)
{
idleEvent.Set();
}
};
wfApp.Run();
// Loop until the workflow completes.
WaitHandle[] handles = new WaitHandle[] { syncEvent, idleEvent };
while (WaitHandle.WaitAny(handles) != 0)
{
// Gather the user input and resume the bookmark.
bool validEntry = false;
while (!validEntry)
{
if (!Int32.TryParse(Console.ReadLine(), out int Guess))
{
Console.WriteLine("Please enter an integer.");
}
else
{
validEntry = true;
wfApp.ResumeBookmark("EnterGuess", Guess);
}
}
}
}
Sub Main()
Dim syncEvent As New AutoResetEvent(False)
Dim idleEvent As New AutoResetEvent(False)
Dim inputs As New Dictionary(Of String, Object)
inputs.Add("MaxNumber", 100)
Dim wfApp As New WorkflowApplication(New Workflow1(), inputs)
wfApp.Completed =
Sub(e As WorkflowApplicationCompletedEventArgs)
Dim Turns As Integer = Convert.ToInt32(e.Outputs("Turns"))
Console.WriteLine("Congratulations, you guessed the number in {0} turns.", Turns)
syncEvent.Set()
End Sub
wfApp.Aborted =
Sub(e As WorkflowApplicationAbortedEventArgs)
Console.WriteLine(e.Reason)
syncEvent.Set()
End Sub
wfApp.OnUnhandledException =
Function(e As WorkflowApplicationUnhandledExceptionEventArgs)
Console.WriteLine(e.UnhandledException)
Return UnhandledExceptionAction.Terminate
End Function
wfApp.Idle =
Sub(e As WorkflowApplicationIdleEventArgs)
idleEvent.Set()
End Sub
wfApp.Run()
' Loop until the workflow completes.
Dim waitHandles As WaitHandle() = New WaitHandle() {syncEvent, idleEvent}
Do While WaitHandle.WaitAny(waitHandles) <> 0
'Gather the user input and resume the bookmark.
Dim validEntry As Boolean = False
Do While validEntry = False
Dim Guess As Integer
If Int32.TryParse(Console.ReadLine(), Guess) = False Then
Console.WriteLine("Please enter an integer.")
Else
validEntry = True
wfApp.ResumeBookmark("EnterGuess", Guess)
End If
Loop
Loop
End Sub