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

  1. Aprire la soluzione dall'argomento Procedura: creare un'attività precedente tramite Visual Studio 2012.

  2. 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 .

  3. 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.

  4. 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.

  5. 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

  1. 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 con FlowchartNumberGuessWorkflow, SequentialNumberGuessWorkflowo StateMachineNumberGuessWorkflow, a seconda del flusso di lavoro completato nel passaggio precedente Procedura: creare un flusso di lavoro. Se non si sostituisce Workflow1 , 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

  1. Aggiungere la seguente istruzione all'inizio del file Program.cs o Module1.vb dopo le istruzioni using o Imports esistenti.

  2. 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 con FlowchartNumberGuessWorkflow, SequentialNumberGuessWorkflowo 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.

    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

  1. 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

  1. 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)
    
  2. 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 usa idleEvent e syncEvent 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.

  3. Rimuovere la chiamata al metodo WaitOnee 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

  1. Fare clic con il pulsante destro del mouse su NumberGuessWorkflowHost in Esplora soluzioni e selezionare Imposta come progetto di avvio.

  2. 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 con FlowchartNumberGuessWorkflow, SequentialNumberGuessWorkflowo StateMachineNumberGuessWorkflow, 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, SequentialNumberGuessWorkflowo 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

Vedi anche