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
Abra a solução do tópico anterior, Como criar uma atividade, usando o Visual Studio 2012.
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.
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.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.
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
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 porFlowchartNumberGuessWorkflow
,SequentialNumberGuessWorkflow
, orStateMachineNumberGuessWorkflow
, dependendo de qual fluxo de trabalho você concluiu na etapa anterior, Como criar um fluxo de trabalho. Se você não substituirWorkflow1
, receberá erros de compilação quando tentar criar ou executar o fluxo de trabalho.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()
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
Adicione a seguinte instrução na parte superior do Program.cs ou Module1.vb abaixo das instruções
using
ouImports
.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 porFlowchartNumberGuessWorkflow
,SequentialNumberGuessWorkflow
, orStateMachineNumberGuessWorkflow
, dependendo de qual fluxo de trabalho você concluiu na etapa anterior, Como criar um fluxo de trabalho. Se você não substituirWorkflow1
, 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(_wf, 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
Modifique o manipulador Completed para recuperar e exibir o número de sequências usadas pelo fluxo de trabalho.
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
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)
Adicione o manipulador Idle a seguir abaixo dos manipuladores existentes do ciclo de vida de fluxo de trabalho em
Main
.Idle = delegate (WorkflowApplicationIdleEventArgs e) { idleEvent.Set(); } };
wfApp.Idle = Sub(e As WorkflowApplicationIdleEventArgs) idleEvent.Set() End Sub
Cada vez que o fluxo de trabalho fica ocioso aguardando o próximo palpite, esse identificador é chamado e o
idleAction
AutoResetEvent é definido. O código na etapa a seguir usaidleEvent
esyncEvent
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.
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) { 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
Para criar e executar o aplicativo
Clique com o botão direito do mouse em NumberGuessWorkflowHost no Gerenciador de Soluções e selecione Definir como Projeto de Inicialização.
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 porFlowchartNumberGuessWorkflow
,SequentialNumberGuessWorkflow
ouStateMachineNumberGuessWorkflow
, dependendo de qual estilo de fluxo de trabalho você deseja.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)
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(_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