Procedura: Eseguire un flusso di lavoro
Questo argomento è una continuazione dell'esercitazione introduttiva di Windows Workflow Foundation e illustra come creare un host di flusso di lavoro ed eseguire il flusso di lavoro definito nell'argomento How to: Create a Workflow precedente.
Nota
Ogni argomento nell'Esercitazione introduttiva dipende dagli argomenti precedenti. Per completare questo argomento, è necessario completare prima How to: Create an Activity e How to: Create a Workflow.
Per creare il progetto host del flusso di lavoro
Aprire la soluzione dall'argomento Procedura: creare un'attività precedente tramite Visual Studio 2012.
Fare clic con il pulsante destro del mouse sulla soluzione WF45GettingStartedTutorial in Esplora soluzioni e scegliere Aggiungi, Nuovo progetto.
Suggerimento
Se la finestra Esplora soluzioni non è visualizzata, scegliere Esplora soluzioni dal menu Visualizza .
Nel nodo Modelli installati selezionare Visual C#, Flusso di lavoro (oppure Visual Basic, Flusso di lavoro).
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 flusso di lavoro dall'elenco Flusso di lavoro . Digitare
NumberGuessWorkflowHost
nella casella Nome , quindi fare clic su OK. In questo modo verrà creata un'applicazione flusso di lavoro iniziale con supporto per l'hosting del flusso di lavoro di base. Il codice host di base viene modificato e usato per eseguire l'applicazione flusso di lavoro.Fare clic con il pulsante destro del mouse sul progetto NumberGuessWorkflowHost appena aggiunto in Esplora soluzioni e selezionare Aggiungi riferimento. Scegliere Soluzione nell'elenco Aggiungi riferimento , selezionare la casella di controllo accanto a NumberGuessWorkflowActivities, quindi scegliere OK.
Fare clic con il pulsante destro del mouse su Workflow1.xaml in Esplora soluzioni e scegliere Elimina. Fare clic su OK per confermare.
Per modificare il codice host del flusso di lavoro
Fare doppio clic su Program.cs o Module1.vb in Esplora soluzioni per visualizzare il codice.
Suggerimento
Se la finestra Esplora soluzioni non è visualizzata, scegliere Esplora soluzioni dal menu Visualizza .
Poiché questo progetto viene creato usando il modello Applicazione console flusso di lavoro , Program.cs o Module1.vb contiene il seguente codice host del flusso di lavoro di base.
' 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);
Questo codice host generato usa WorkflowInvoker. WorkflowInvoker offre un modo semplice per richiamare un flusso di lavoro come se fosse una chiamata a un metodo e può essere usato solo per i flussi di lavoro che non usano la persistenza. WorkflowApplication fornisce un modello più dettagliato per l'esecuzione di flussi di lavoro che include la notifica degli eventi del ciclo di vita, il controllo di esecuzione, la ripresa del segnalibro e la persistenza. In questo esempio vengono usati i segnalibri e l'oggetto WorkflowApplication viene usato per ospitare il flusso di lavoro. Aggiungere la seguente istruzione
using
o Imports all'inizio del file Program.cs o Module1.vb dopo le istruzioni using o Imports esistenti.Imports NumberGuessWorkflowActivities Imports System.Threading
using NumberGuessWorkflowActivities; using System.Threading;
Sostituire le righe di codice che usano l'oggetto WorkflowInvoker con il seguente codice host WorkflowApplication di base. In questo codice host di esempio vengono illustrati i passaggi di base per ospitare e richiamare un flusso di lavoro, ma non è contenuta ancora la funzionalità per eseguire correttamente il flusso di lavoro da questo argomento. Nei seguenti passaggi il codice di base viene modificato e vengono aggiunte funzionalità aggiuntive fino a quando l'applicazione non viene completata.
Nota
Occorre sostituire
Workflow1
in questi esempi conFlowchartNumberGuessWorkflow
,SequentialNumberGuessWorkflow
oStateMachineNumberGuessWorkflow
, a seconda del flusso di lavoro completato nel passaggio precedente Procedura: creare un flusso di lavoro. Se non si sostituisceWorkflow1
, si verificheranno degli errori di compilazione quando si tenterà di compilare o eseguire il flusso di lavoro.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()
Questo codice crea un oggetto WorkflowApplication, sottoscrive tre eventi del ciclo di vita del flusso di lavoro, avvia il flusso di lavoro con una chiamata al metodo Run, quindi attende il completamento del flusso di lavoro. Quando il flusso di lavoro viene completato, l'oggetto AutoResetEvent viene impostato e l'applicazione host viene completata.
Per impostare gli argomenti di input di un flusso di lavoro
Aggiungere la seguente istruzione all'inizio del file Program.cs o Module1.vb dopo le istruzioni
using
oImports
esistenti.Sostituire la riga di codice che crea il nuovo oggetto WorkflowApplication con il codice seguente che crea e passa un dizionario di parametri al flusso di lavoro quando viene creato.
Nota
Sostituire
Workflow1
in questi esempi conFlowchartNumberGuessWorkflow
,SequentialNumberGuessWorkflow
oStateMachineNumberGuessWorkflow
, a seconda del flusso di lavoro completato nel passaggio precedente How to: Create a Workflow . Se non si sostituisceWorkflow1
, si verificheranno degli errori di compilazione quando si tenterà di compilare o eseguire il flusso di lavoro.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)
Questo dizionario contiene un elemento con una chiave di
MaxNumber
. Le chiavi nel dizionario di input corrispondono agli argomenti di input sull'attività radice del flusso di lavoro.MaxNumber
viene usato dal flusso di lavoro per determinare il limite superiore del numero generato casualmente.
Per recuperare gli argomenti di output di un flusso di lavoro
Modificare il gestore Completed per recuperare e visualizzare il numero di turni usati dal flusso di lavoro.
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
Per riprendere un segnalibro
Aggiungere il seguente codice all'inizio del metodo
Main
subito dopo la dichiarazione AutoResetEvent esistente.AutoResetEvent idleEvent = new AutoResetEvent(false);
Dim idleEvent As New AutoResetEvent(False)
Aggiungere il seguente gestore Idle subito dopo i tre gestori del ciclo di vita del flusso di lavoro esistenti in
Main
.Idle = delegate (WorkflowApplicationIdleEventArgs e) { idleEvent.Set(); } };
wfApp.Idle = Sub(e As WorkflowApplicationIdleEventArgs) idleEvent.Set() End Sub
Ogni volta che il flusso di lavoro diventa inattivo nell'attesa del tentativo successivo, viene chiamato questo gestore e viene impostato l'oggetto
idleAction
AutoResetEvent. Il codice nel passaggio seguente usaidleEvent
esyncEvent
per determinare se il flusso di lavoro è in attesa della prossimo tentativo o viene completato.Nota
In questo esempio l'applicazione host usa eventi di reimpostazione automatica nei gestori Completed e Idle per sincronizzare l'applicazione host con lo stato di avanzamento del flusso di lavoro. Non è necessario bloccare e attendere l'inattività del flusso di lavoro prima di riprendere un segnalibro, ma in questo esempio gli eventi di sincronizzazione sono obbligatori affinché l'host sappia se il flusso di lavoro viene completato o se è in attesa di più input dell'utente usando l'oggetto Bookmark. Per altre informazioni, vedere Segnalibri.
Rimuovere la chiamata al metodo
WaitOne
e sostituirla con codice per raccogliere l'input dell'utente e riprendere l'oggetto Bookmark.Rimuovere la seguente riga di codice.
syncEvent.WaitOne();
syncEvent.WaitOne()
Sostituirla con l'esempio seguente.
// 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
Per compilare ed eseguire l'applicazione
Fare clic con il pulsante destro del mouse su NumberGuessWorkflowHost in Esplora soluzioni e selezionare Imposta come progetto di avvio.
Premere CTRL+F5 per compilare ed eseguire l'applicazione. Provare a determinare il numero con meno tentativi possibili.
Per provare l'applicazione con uno degli altri stili del flusso di lavoro, sostituire
Workflow1
nel codice che crea WorkflowApplication conFlowchartNumberGuessWorkflow
,SequentialNumberGuessWorkflow
oStateMachineNumberGuessWorkflow
, a seconda dello stile del flusso di lavoro desiderato.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)
Per istruzioni sull'aggiunta di persistenza a un'applicazione flusso di lavoro, vedere l'argomento successivo, How to: Create and Run a Long Running Workflow.
Esempio
L'esempio seguente è l'elenco di codice per il metodo Main
.
Nota
Sostituire Workflow1
in questi esempi con FlowchartNumberGuessWorkflow
, SequentialNumberGuessWorkflow
o StateMachineNumberGuessWorkflow
, a seconda del flusso di lavoro completato nel passaggio precedente How to: Create a Workflow . Se non si sostituisce Workflow1
, si verificheranno degli errori di compilazione quando si tenterà di compilare o eseguire il flusso di lavoro.
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