Procedimiento para ejecutar un flujo de trabajo
Este tema es una continuación del tutorial introductorio de Windows Workflow Foundation y explica cómo crear un host de flujo de trabajo y ejecutar el flujo de trabajo definido en el tema How to: Create a Workflow anterior.
Nota
Cada uno de los temas del tutorial de introducción depende de los temas anteriores. Para completar este tema, primero debe finalizar How to: Create an Activity y How to: Create a Workflow.
Para crear el proyecto de host de flujo de trabajo
Abra la solución del tema Cómo crear una actividad anterior con Visual Studio 2012.
Haga clic con el botón secundario en la solución WF45GettingStartedTutorial en el Explorador de soluciones y seleccione Agregar, Nuevo proyecto.
Sugerencia
Si no está visible la ventana Explorador de soluciones, seleccione Explorador de soluciones en el menú Ver.
En el nodo Instalado , seleccione Visual C#, Flujo de trabajo (o Visual Basic, Flujo de trabajo).
Nota
En función del lenguaje de programación configurado como lenguaje principal en Visual Studio, es posible que el nodo Visual C# o Visual Basic se encuentre debajo del nodo Otros lenguajes del nodo Instalados.
Asegúrese de que .NET Framework 4.5 está seleccionado en la lista desplegable de versiones de .NET Framework. Seleccione Aplicación de consola de flujos de trabajo en la lista Flujo de trabajo . Escriba
NumberGuessWorkflowHost
en el cuadro Nombre y haga clic en Aceptar. Así se crea una aplicación de flujo de trabajo de inicio con soporte básico de hospedaje de flujo de trabajo. Este código de hospedaje básico se modifica y se usa para ejecutar la aplicación de flujo de trabajo.Haga clic con el botón secundario en el proyecto NumberGuessWorkflowHost recién agregado en el Explorador de soluciones y seleccione Agregar referencia. Seleccione Solución en la lista Agregar referencia , marque la casilla junto NumberGuessWorkflowActivitiesy, a continuación, haga clic en Aceptar.
Haga clic con el botón secundario en Workflow1.xaml en el Explorador de soluciones y elija Eliminar. Haga clic en ACEPTAR para continuar.
Para modificar el código de hospedaje de flujo de trabajo
Haga doble clic en Program.cs o en Module1.vb en el Explorador de soluciones para mostrar el código.
Sugerencia
Si no está visible la ventana Explorador de soluciones, seleccione Explorador de soluciones en el menú Ver.
Dado que este proyecto se creó con la plantilla Aplicación de consola de flujos de trabajo , Program.cs o Module1.vb , contiene el siguiente código básico de hospedaje de flujo de trabajo.
' 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 hospedaje generado usa WorkflowInvoker. WorkflowInvoker proporciona una manera sencilla de invocar un flujo de trabajo como si fuera una llamada al método y se puede usar solo para los flujos de trabajo que no usan la persistencia. WorkflowApplication proporciona un modelo más enriquecido para ejecutar flujos de trabajo que incluye notificación de eventos de ciclo de vida, control de ejecución, reanudación de marcadores y persistencia. Este ejemplo usa marcadores y WorkflowApplication se usa para hospedar el flujo de trabajo. Agregue la siguiente instrucción
using
o Imports al principio de Program.cs o Module1.vb debajo de las instrucciones using o Imports existentes.Imports NumberGuessWorkflowActivities Imports System.Threading
using NumberGuessWorkflowActivities; using System.Threading;
Reemplace las líneas de código que usan WorkflowInvoker por el siguiente código básico de hospedaje WorkflowApplication . Este código de hospedaje de ejemplo muestra los pasos básicos para hospedar e invocar un flujo de trabajo, pero no contiene, sin embargo, la funcionalidad necesaria para ejecutar correctamente el flujo de trabajo en este tema. En los pasos que figuran a continuación, el código básico se modifica y se agregan características adicionales hasta completar la aplicación.
Nota:
Debe reemplazar
Workflow1
en estos ejemplos porFlowchartNumberGuessWorkflow
,SequentialNumberGuessWorkflow
oStateMachineNumberGuessWorkflow
, en función del flujo de trabajo que completara en el paso anterior de Procedimiento: Creación de un flujo de trabajo. Si no reemplazaWorkflow1
, se producirán errores de compilación cuando intente compilar o ejecutar el flujo de trabajo.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()
Este código crea un objeto WorkflowApplication, se suscribe a tres eventos de ciclo de vida de flujo de trabajo, inicia el flujo de trabajo con una llamada a Runy espera a que el flujo de trabajo se complete. Cuando el flujo de trabajo finaliza, se establece AutoResetEvent y se completa la aplicación host.
Para definir argumentos de entrada de un flujo de trabajo
Agregue la siguiente instrucción al principio de Program.cs o Module1.vb debajo de las instrucciones
using
oImports
existentes.Reemplace la línea de código que crea el nuevo WorkflowApplication con el siguiente código que crea y pasa un diccionario de parámetros al flujo de trabajo cuando se crea.
Nota
Reemplace
Workflow1
en estos ejemplos porFlowchartNumberGuessWorkflow
,SequentialNumberGuessWorkflow
oStateMachineNumberGuessWorkflow
, en función del flujo de trabajo que completara en el paso How to: Create a Workflow anterior. Si no reemplazaWorkflow1
, se producirán errores de compilación cuando intente compilar o ejecutar el flujo de trabajo.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 diccionario contiene un elemento con una clave de
MaxNumber
. Las claves del diccionario de entrada corresponden a argumentos de entrada en la actividad raíz del flujo de trabajo. El flujo de trabajo usaMaxNumber
para determinar el límite superior para el número generado aleatoriamente.
Para recuperar parámetros de salida de un flujo de trabajo
Modifique el controlador Completed para recuperar y mostrar el número de intentos que usó el flujo de trabajo.
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 reanudar un marcador
Agregue el siguiente código en la parte superior del método
Main
justo después de la declaración AutoResetEvent existente.AutoResetEvent idleEvent = new AutoResetEvent(false);
Dim idleEvent As New AutoResetEvent(False)
Agregue el siguiente controlador Idle justo después de los tres controladores de ciclo de vida de flujo de trabajo existentes en
Main
.Idle = delegate (WorkflowApplicationIdleEventArgs e) { idleEvent.Set(); } };
wfApp.Idle = Sub(e As WorkflowApplicationIdleEventArgs) idleEvent.Set() End Sub
Cada vez que el flujo de trabajo se vuelve inactivo a la espera de la suposición siguiente, se llama a este controlador y se establece
idleAction
AutoResetEvent. El código en el siguiente paso usaidleEvent
ysyncEvent
para determinar si el flujo de trabajo está esperando la siguiente suposición o si se ha completado.Nota
En este ejemplo, la aplicación host usa eventos de restablecimiento automático en los controladores Completed y Idle para sincronizar la aplicación host con el progreso del flujo de trabajo. No es necesario bloquear y esperar a que el flujo de trabajo se vuelva inactivo para reanudar un marcador, aunque en este ejemplo los eventos de sincronización resultan necesarios para que el host sepa si se ha completado el flujo de trabajo o si está esperando más entradas de usuario mediante Bookmark. Para más información, consulte Marcadores.
Quite la llamada a
WaitOne
y reemplácela con código para recopilar la entrada del usuario y reanudar el marcador Bookmark.Quite la siguiente línea de código.
syncEvent.WaitOne();
syncEvent.WaitOne()
Reemplácela con el siguiente ejemplo.
// 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 generar y ejecutar la aplicación
Haga clic con el botón secundario en NumberGuessWorkflowHost en el Explorador de soluciones y seleccione Establecer como proyecto de inicio.
Presione CTRL+F5 para compilar y ejecutar la aplicación. Intente adivinar el número en los menos intentos posibles.
Para probar la aplicación con uno de los demás estilos de flujo de trabajo, reemplace
Workflow1
en el código que crea WorkflowApplication porFlowchartNumberGuessWorkflow
,SequentialNumberGuessWorkflow
oStateMachineNumberGuessWorkflow
, en función del estilo de flujo de trabajo que desee.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 obtener instrucciones sobre cómo agregar la persistencia a una aplicación de flujo de trabajo, consulte el siguiente tema: How to: Create and Run a Long Running Workflow.
Ejemplo
En el ejemplo siguiente se muestra la lista de código completa del método Main
.
Nota
Reemplace Workflow1
en estos ejemplos por FlowchartNumberGuessWorkflow
, SequentialNumberGuessWorkflow
o StateMachineNumberGuessWorkflow
, en función del flujo de trabajo que completara en el paso How to: Create a Workflow anterior. Si no reemplaza Workflow1
, se producirán errores de compilación cuando intente compilar o ejecutar el flujo de trabajo.
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