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

  1. Abra la solución del tema Cómo crear una actividad anterior con Visual Studio 2012.

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

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

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

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

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

    Reemplace Workflow1 en estos ejemplos por FlowchartNumberGuessWorkflow, SequentialNumberGuessWorkflowo 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.

    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()
    

    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

  1. Agregue la siguiente instrucción al principio de Program.cs o Module1.vb debajo de las instrucciones using o Imports existentes.

    using System.Collections.Generic;
    using System.Threading;
    
    Imports System.Collections.Generic
    
  2. 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 por FlowchartNumberGuessWorkflow, SequentialNumberGuessWorkflowo 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.

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

  1. Modifique el controlador Completed para recuperar y mostrar el número de intentos que usó el flujo de trabajo.

    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 reanudar un marcador

  1. 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)
    
  2. Agregue el siguiente controlador Idle justo después de los tres controladores de ciclo de vida de flujo de trabajo existentes en Main.

    wfApp.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 idleActionAutoResetEvent. El código en el siguiente paso usa idleEvent y syncEvent 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.

  3. Quite la llamada a WaitOney 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)
        {
            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 generar y ejecutar la aplicación

  1. Haga clic con el botón secundario en NumberGuessWorkflowHost en el Explorador de soluciones y seleccione Establecer como proyecto de inicio.

  2. 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 por FlowchartNumberGuessWorkflow, SequentialNumberGuessWorkflowo StateMachineNumberGuessWorkflow, en función del estilo de flujo de trabajo que desee.

    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 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, SequentialNumberGuessWorkflowo 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 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

Consulte también