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 .
Nota
Cada tópico no tutorial de Introdução depende dos tópicos anteriores. Para concluir este tópico, você deve primeiro concluir Como: Criar uma atividade e Como: Criar um fluxo de trabalho.
Para criar o projeto de host do 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 do mouse na solução WF45GettingStartedTutorial no Gerenciador de Soluções e selecione Adicionar, Novo Projeto.
Gorjeta
Se a janela Gerenciador de Soluções não for exibida, selecione Gerenciador de Soluções no menu Exibir .
No nó Instalado, selecione Visual C#, Workflow (ou Visual Basic, Workflow).
Nota
Dependendo de qual linguagem de programação é configurada como a linguagem principal no Visual Studio, o nó Visual C# ou Visual Basic pode estar sob o nó Outras linguagens no nó instalado .
Verifique se o .NET Framework 4.5 está selecionado na lista suspensa de versão do .NET Framework. Selecione Aplicativo de console de 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 do mouse no projeto NumberGuessWorkflowHost recém-adicionado 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 do mouse 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.
Gorjeta
Se a janela Gerenciador de Soluções não for exibida, selecione Gerenciador de Soluções no menu Exibir .
Como este projeto foi criado usando o modelo Aplicativo de Console de Fluxo de Trabalho, Program.cs ou Module1.vb contém o seguinte código básico de hospedagem de fluxo de trabalho.
' 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);
Este código de hospedagem gerado usa WorkflowInvoker. WorkflowInvoker Fornece uma maneira simples de invocar um fluxo de trabalho como se fosse uma chamada de método e pode ser usado apenas para fluxos de trabalho que não usam persistência. WorkflowApplication Fornece um modelo mais avançado para a execução de fluxos de trabalho que inclui notificação de eventos do ciclo de vida, controle de execução, retomada de marcadores e persistência. Este exemplo usa marcadores e WorkflowApplication é usado para hospedar o fluxo de trabalho. Adicione a seguinte
using
instrução ou Imports na parte superior de Program.cs ou Module1.vb abaixo das instruções de uso ou Imports existentes.Imports NumberGuessWorkflowActivities Imports System.Threading
using NumberGuessWorkflowActivities; using System.Threading;
Substitua as linhas de código que usam WorkflowInvoker com o seguinte código de hospedagem básico WorkflowApplication . Este código de hospedagem de exemplo demonstra as etapas básicas para hospedar e invocar 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 recursos adicionais são adicionados até que o aplicativo seja concluído.
Nota
Nestes exemplos, você deve substituir
Workflow1
por ,SequentialNumberGuessWorkflow
ouStateMachineNumberGuessWorkflow
, dependendo do fluxo de trabalho concluído na etapa anterior Como: Criar um fluxo de trabalho.FlowchartNumberGuessWorkflow
Se você não substituirWorkflow1
, receberá erros de compilação quando tentar compilar 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 do fluxo de trabalho, inicia o fluxo de trabalho com uma chamada para Rune aguarda a conclusão do fluxo de trabalho. Quando o fluxo de trabalho é 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 de Program.cs ou Module1.vb abaixo das instruções ou existentes
using
Imports
.Substitua a linha de código que cria o novo WorkflowApplication pelo código a seguir que cria e passa um dicionário de parâmetros para o fluxo de trabalho quando ele é criado.
Nota
Substitua
Workflow1
nestes exemplos porFlowchartNumberGuessWorkflow
,SequentialNumberGuessWorkflow
ouStateMachineNumberGuessWorkflow
, dependendo do fluxo de trabalho concluído na etapa anterior Como: Criar um fluxo de trabalho . Se você não substituirWorkflow1
, receberá erros de compilação quando tentar compilar 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 de
MaxNumber
. As chaves no 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 Completed manipulador para recuperar e exibir o número de voltas 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 marcador
Adicione o seguinte código na parte superior do
Main
método logo após a declaração existente AutoResetEvent .AutoResetEvent idleEvent = new AutoResetEvent(false);
Dim idleEvent As New AutoResetEvent(False)
Adicione o seguinte Idle manipulador logo abaixo dos três manipuladores de ciclo de vida do fluxo de trabalho existentes no
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 a próxima suposição, esse manipulador é chamado e o
idleAction
AutoResetEvent é definido. O código na etapa a seguir usaidleEvent
esyncEvent
para determinar se o fluxo de trabalho está aguardando a próxima suposição ou está concluído.Nota
Neste exemplo, o aplicativo host usa eventos de redefinição automática nos Completed manipuladores e Idle para sincronizar o aplicativo host com o progresso do fluxo de trabalho. Não é necessário bloquear e aguardar que o fluxo de trabalho fique ocioso antes de retomar um marcador, mas neste exemplo os eventos de sincronização são necessários para que o host saiba se o fluxo de trabalho está completo ou se está aguardando mais entrada do usuário usando o Bookmark. Para obter mais informações, consulte Favoritos.
Remova a chamada para
WaitOne
, e substitua-a por código para coletar a entrada do usuário e retomar o Bookmark.Remova a seguinte linha de código.
syncEvent.WaitOne();
syncEvent.WaitOne()
Substitua-o 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 adivinhar o número no menor número de voltas possível.
Para experimentar o aplicativo por um dos outros estilos de fluxo de trabalho, substitua
Workflow1
o código que cria o WorkflowApplication comFlowchartNumberGuessWorkflow
,SequentialNumberGuessWorkflow
ouStateMachineNumberGuessWorkflow
, dependendo do estilo de fluxo de trabalho desejado.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 longa duração.
Exemplo
O exemplo a seguir é a listagem de código completa para o Main
método.
Nota
Substitua Workflow1
nestes exemplos por FlowchartNumberGuessWorkflow
, SequentialNumberGuessWorkflow
ou StateMachineNumberGuessWorkflow
, dependendo do fluxo de trabalho concluído na etapa anterior Como: Criar um fluxo de trabalho . Se você não substituir Workflow1
, receberá erros de compilação quando tentar compilar 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