Como: executar um fluxo de trabalho

Este tópico é uma continuação do Tutorial de introdução do Windows Workflow Foundation e discute como criar um host de fluxo de trabalho e executar o fluxo de trabalho definido no tópico anterior Como criar um fluxo de trabalho.

Observação

Cada tópico do tutorial de Introdução depende dos tópicos anteriores. Para concluir este tópico, primeiro você deve concluir Como criar uma atividade e Como criar um fluxo de trabalho.

Para criar o projeto de host de fluxo de trabalho

  1. Abra a solução do tópico anterior, Como criar uma atividade, usando o Visual Studio 2012.

  2. Clique com o botão direito na solução WF45GettingStartedTutorial no Gerenciador de Soluções e selecione Adicionar, Novo projeto.

    Dica

    Se a janela do Gerenciador de Soluções não abrir, selecione Gerenciador de Soluções no menu Exibir.

  3. No nó Instalado, selecione Visual C#, Fluxo de trabalho (ou Visual Basic, Fluxo de trabalho).

    Observação

    Dependendo da linguagem de programação que esteja configurada como linguagem primária no Visual Studio, o nó Visual C# ou Visual Basic poderá estar sob o nó Outras Linguagens no nó Instalado.

    Certifique-se de que o .NET Framework 4.5 esteja selecionado na lista suspensa de versões do .NET Framework. Selecione Aplicativo de Console do Fluxo de Trabalho na lista Fluxo de trabalho. Digite NumberGuessWorkflowHost na caixa Nome e clique em OK. Isso cria um aplicativo de fluxo de trabalho inicial com suporte básico de hospedagem de fluxo de trabalho. Esse código básico de hospedagem é modificado e usado para executar o aplicativo de fluxo de trabalho.

  4. Clique com o botão direito no projeto recém-adicionado NumberGuessWorkflowHost no Gerenciador de Soluções e selecione Adicionar Referência. Selecione Solução na lista Adicionar Referência, marque a caixa de seleção ao lado de NumberGuessWorkflowActivities e clique em OK.

  5. Clique com o botão direito em Workflow1.xaml no Gerenciador de Soluções e escolha Excluir. Clique em OK para confirmar.

Para modificar o código de hospedagem do fluxo de trabalho

  1. Clique duas vezes em Program.cs ou Module1.vb no Gerenciador de Soluções para exibir o código.

    Dica

    Se a janela do Gerenciador de Soluções não abrir, selecione Gerenciador de Soluções no menu Exibir.

    Como esse projeto foi criado usando o modelo Aplicativo de Console do Fluxo de Trabalho, Program.cs ou Module1.vb contém o código de hospedagem de fluxo de trabalho básico a seguir.

    ' 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);
    

    Esse código de hospedagem gerado usa WorkflowInvoker. WorkflowInvoker fornece uma maneira simples para chamar um fluxo de trabalho como se fosse uma chamada de método e pode ser usado somente para os fluxos de trabalho que não usam persistência. WorkflowApplication fornece um modelo mais avançado para executar fluxos de trabalho que incluem a notificação de eventos de ciclo de vida, o controle de execução, o reinício do indicador e a persistência. Este exemplo usa indicadores e o WorkflowApplication é usado para hospedar o fluxo de trabalho. Adicione a seguinte instrução using ou Imports na parte superior de Program.cs ou Module1.vb abaixo das instruções using ou Imports.

    Imports NumberGuessWorkflowActivities
    Imports System.Threading
    
    using NumberGuessWorkflowActivities;
    using System.Threading;
    

    Substituir as linhas de código que usam WorkflowInvoker com o código de hospedagem básica WorkflowApplication a seguir. Este código de hospedagem de exemplo demonstra as etapas básicas para hospedar e chamar um fluxo de trabalho, mas ainda não contém a funcionalidade para executar com êxito o fluxo de trabalho a partir deste tópico. Nas etapas a seguir, esse código básico é modificado e os recursos adicionais são adicionados até que o aplicativo esteja concluído.

    Observação

    Substitua Workflow1 nestes exemplos por FlowchartNumberGuessWorkflow, SequentialNumberGuessWorkflow, or StateMachineNumberGuessWorkflow, dependendo de qual fluxo de trabalho você concluiu na etapa anterior, Como criar um fluxo de trabalho. Se você não substituir Workflow1, receberá erros de compilação quando tentar criar ou executar o fluxo de trabalho.

    AutoResetEvent syncEvent = new AutoResetEvent(false);
    
    WorkflowApplication wfApp =
        new WorkflowApplication(new Workflow1());
    
    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()
    

    Esse código cria um WorkflowApplication, assina três eventos do ciclo de vida de fluxo de trabalho, inicia o fluxo de trabalho com uma chamada para Run e aguarda que o fluxo de trabalho seja concluído. Quando o fluxo de trabalho estiver concluído, o AutoResetEvent é definido e o aplicativo host é concluído.

Para definir argumentos de entrada de um fluxo de trabalho

  1. Adicione a seguinte instrução na parte superior do Program.cs ou Module1.vb abaixo das instruções using ou Imports.

    using System.Collections.Generic;
    using System.Threading;
    
    Imports System.Collections.Generic
    
  2. Substitua a linha de código que cria uma nova WorkflowApplication pelo código a seguir que cria e passa um dicionário dos parâmetros para o fluxo de trabalho quando ele é criado.

    Observação

    Substitua Workflow1 nestes exemplos por FlowchartNumberGuessWorkflow, SequentialNumberGuessWorkflow, or StateMachineNumberGuessWorkflow, dependendo de qual fluxo de trabalho você concluiu na etapa anterior, Como criar um fluxo de trabalho. Se você não substituir Workflow1, receberá erros de compilação quando tentar criar ou executar o fluxo de trabalho.

    var inputs = new Dictionary<string, object>() { { "MaxNumber", 100 } };
    
    WorkflowApplication wfApp =
        new WorkflowApplication(new Workflow1(), inputs);
    
    Dim inputs As New Dictionary(Of String, Object)
    inputs.Add("MaxNumber", 100)
    
    Dim wfApp As New WorkflowApplication(New Workflow1(), inputs)
    

    Este dicionário contém um elemento com uma chave MaxNumber. As chaves do dicionário de entrada correspondem a argumentos de entrada na atividade raiz do fluxo de trabalho. MaxNumber é usado pelo fluxo de trabalho para determinar o limite superior para o número gerado aleatoriamente.

Para recuperar argumentos de saída de um fluxo de trabalho

  1. Modifique o manipulador Completed para recuperar e exibir o número de sequências usadas pelo fluxo de trabalho.

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

Para retomar um indicador

  1. Adicione o código a seguir na parte superior do método Main imediatamente após a instrução AutoResetEvent existente.

    AutoResetEvent idleEvent = new AutoResetEvent(false);
    
    Dim idleEvent As New AutoResetEvent(False)
    
  2. Adicione o manipulador Idle a seguir abaixo dos manipuladores existentes do ciclo de vida de fluxo de trabalho em Main.

    wfApp.Idle = delegate (WorkflowApplicationIdleEventArgs e)
    {
        idleEvent.Set();
    };
    
    wfApp.Idle = _
        Sub(e As WorkflowApplicationIdleEventArgs)
            idleEvent.Set()
        End Sub
    

    Cada vez que o fluxo de trabalho ficar ocioso aguardando o próximo palpite, esse identificador é chamado e o idleActionAutoResetEvent é definido. O código na etapa a seguir usa idleEvent e syncEvent para determinar se o fluxo de trabalho está esperando o próximo palpite ou está concluído.

    Observação

    Neste exemplo, o aplicativo host usa eventos de redefinição automática nos manipuladores Completed e de Idle para sincronizar o aplicativo host com o progresso do fluxo de trabalho. Não é necessário bloquear e esperar que o fluxo de trabalho fique inativo antes de retomar um indicador, mas, nesse exemplo, os eventos de sincronização são necessários para que o host saiba se o fluxo de trabalho está concluído ou se está aguardando mais entrada do usuário usando o Bookmark. Para obter mais informações, consulte Indicadores.

  3. Remova a chamada para WaitOne e substitua-a pelo código para coletar entrada do usuário e retomar o Bookmark.

    Remova a seguinte linha de código.

    syncEvent.WaitOne();
    
    syncEvent.WaitOne()
    

    Substitua-a pelo exemplo a seguir.

    // 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)
        {
            int Guess;
            if (!Int32.TryParse(Console.ReadLine(), out 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
    

Para criar e executar o aplicativo

  1. Clique com o botão direito do mouse em NumberGuessWorkflowHost no Gerenciador de Soluções e selecione Definir como Projeto de Inicialização.

  2. Pressione CTRL+F5 para compilar e executar o aplicativo. Tente determinar o número no menor número de sequências possível.

    Para testar o aplicativo com um dos outros estilos de fluxo de trabalho, substitua Workflow1 no código que cria o WorkflowApplication por FlowchartNumberGuessWorkflow, SequentialNumberGuessWorkflow ou StateMachineNumberGuessWorkflow, dependendo de qual estilo de fluxo de trabalho você deseja.

    var inputs = new Dictionary<string, object>() { { "MaxNumber", 100 } };
    
    WorkflowApplication wfApp =
        new WorkflowApplication(new Workflow1(), inputs);
    
    Dim inputs As New Dictionary(Of String, Object)
    inputs.Add("MaxNumber", 100)
    
    Dim wfApp As New WorkflowApplication(New Workflow1(), inputs)
    

    Para obter instruções sobre como adicionar persistência a um aplicativo de fluxo de trabalho, consulte o próximo tópico, Como criar e executar um fluxo de trabalho de execução prolongada.

Exemplo

O exemplo a seguir é a listagem de código completa para o método Main.

Observação

Substitua Workflow1 nestes exemplos por FlowchartNumberGuessWorkflow, SequentialNumberGuessWorkflow, or StateMachineNumberGuessWorkflow, dependendo de qual fluxo de trabalho você concluiu na etapa anterior, Como criar um fluxo de trabalho. Se você não substituir Workflow1, receberá erros de compilação quando tentar criar ou executar o fluxo de trabalho.

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 WorkflowApplication(new Workflow1(), inputs);

    wfApp.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.Aborted = delegate (WorkflowApplicationAbortedEventArgs e)
    {
        Console.WriteLine(e.Reason);
        syncEvent.Set();
    };

    wfApp.OnUnhandledException = delegate (WorkflowApplicationUnhandledExceptionEventArgs e)
    {
        Console.WriteLine(e.UnhandledException.ToString());
        return UnhandledExceptionAction.Terminate;
    };

    wfApp.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)
        {
            int Guess;
            if (!Int32.TryParse(Console.ReadLine(), out 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

Confira também