Usar WorkflowInvoker y WorkflowApplicationUsing WorkflowInvoker and WorkflowApplication

Windows Workflow Foundation (WF) proporciona varios métodos para hospedar flujos de trabajo.Windows Workflow Foundation (WF) provides several methods of hosting workflows. 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.WorkflowInvoker provides a simple way for invoking a workflow as if it were a method call and can be used only for workflows that do not use persistence. 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.WorkflowApplication provides a richer model for executing workflows that includes notification of lifecycle events, execution control, bookmark resumption, and persistence. WorkflowServiceHost proporciona compatibilidad para las actividades de mensajería y se usa principalmente con servicios de flujo de trabajo.WorkflowServiceHost provides support for messaging activities and is primarily used with workflow services. Este tema presenta el hospedaje del flujo de trabajo con WorkflowInvoker y WorkflowApplication.This topic introduces you to workflow hosting with WorkflowInvoker and WorkflowApplication. Para obtener más información sobre el hospedaje de WorkflowServiceHostflujos de trabajo con, vea Introducción a los servicios de flujo de trabajo y host Workflow Services.For more information about hosting workflows with WorkflowServiceHost, see Workflow Services and Hosting Workflow Services Overview.

Usar WorkflowInvokerUsing WorkflowInvoker

WorkflowInvoker proporciona un modelo para ejecutar un flujo de trabajo como si fuera una llamada al método.WorkflowInvoker provides a model for executing a workflow as if it were a method call. Para invocar un flujo de trabajo mediante WorkflowInvoker, llame al método Invoke y pase la definición del flujo de trabajo que se vaya a invocar.To invoke a workflow using WorkflowInvoker, call the Invoke method and pass in the workflow definition of the workflow to invoke. En este ejemplo, se invoca una actividad WriteLine mediante WorkflowInvoker.In this example, a WriteLine activity is invoked using WorkflowInvoker.

Activity wf = new WriteLine
{
    Text = "Hello World."
};

WorkflowInvoker.Invoke(wf);

Cuando se invoca un flujo de trabajo con WorkflowInvoker, el flujo de trabajo se ejecuta en el subproceso que realiza la llamada y el método Invoke se bloquea hasta que el flujo de trabajo haya finalizado, incluido el tiempo de inactividad.When a workflow is invoked using WorkflowInvoker, the workflow executes on the calling thread and the Invoke method blocks until the workflow is complete, including any idle time. Para configurar un intervalo de tiempo de espera en el que se debe completar el flujo de trabajo, use una de las sobrecargas Invoke que tome un parámetro TimeSpan.To configure a time-out interval in which the workflow must complete, use one of the Invoke overloads that takes a TimeSpan parameter. En este ejemplo, se invoca un flujo de trabajo dos veces con dos intervalos de tiempo de espera diferentes.In this example, a workflow is invoked twice with two different time-out intervals. El primer flujo de trabajo se completa, pero el segundo no.The first workflow complets, but the second does not.

Activity wf = new Sequence()
{
    Activities = 
    {
        new WriteLine()
        {
            Text = "Before the 1 minute delay."
        },
        new Delay()
        {
            Duration = TimeSpan.FromMinutes(1)
        },
        new WriteLine()
        {
            Text = "After the 1 minute delay."
        }
    }
};

// This workflow completes successfully.
WorkflowInvoker.Invoke(wf, TimeSpan.FromMinutes(2));

// This workflow does not complete and a TimeoutException
// is thrown.
try
{
    WorkflowInvoker.Invoke(wf, TimeSpan.FromSeconds(30));
}
catch (TimeoutException ex)
{
    Console.WriteLine(ex.Message);
}

Nota

La excepción TimeoutException solo se produce si se agota el tiempo de espera y el flujo de trabajo queda inactivo durante la ejecución.The TimeoutException is only thrown if the time-out interval elapses and the workflow becomes idle during execution. Un flujo de trabajo que tarda en completarse más tiempo que el especificado por el intervalo de tiempo de espera se completa correctamente si el flujo de trabajo no queda inactivo.A workflow that takes longer than the specified time-out interval to complete completes successfully if the workflow does not become idle.

WorkflowInvoker también proporciona versiones asincrónicas del método de invocación.WorkflowInvoker also provides asynchronous versions of the invoke method. Para obtener más información, vea InvokeAsync y BeginInvoke.For more information, see InvokeAsync and BeginInvoke.

Definir argumentos de entrada de un flujo de trabajoSetting Input Arguments of a Workflow

Los datos se pueden pasar a un flujo de trabajo mediante un diccionario de parámetros de entrada, con claves por nombre de argumento, que se asignan a los argumentos de entrada del flujo de trabajo.Data can be passed into a workflow using a dictionary of input parameters, keyed by argument name, that map to the input arguments of the workflow. En este ejemplo, se invoca WriteLine y el valor de su argumento Text se especifica con el diccionario de parámetros de entrada.In this example, a WriteLine is invoked and the value for its Text argument is specified using the dictionary of input parameters.

Activity wf = new WriteLine();

Dictionary<string, object> inputs = new Dictionary<string, object>();
inputs.Add("Text", "Hello World.");

WorkflowInvoker.Invoke(wf, inputs);

Recuperar argumentos de salida de un flujo de trabajoRetrieving Output Arguments of a Workflow

Los parámetros de salida de un flujo de trabajo se pueden obtener usando el diccionario de salidas que se devuelve de la llamada a Invoke.The output parameters of a workflow can be obtained using the outputs dictionary that is returned from the call to Invoke. En el siguiente ejemplo se invoca un flujo de trabajo formado por una sola actividad Divide que tiene dos argumentos de entrada y dos argumentos de salida.The following example invokes a workflow consisting of a single Divide activity that has two input arguments and two output arguments. Cuando se invoca el flujo de trabajo, se pasa el diccionario de arguments que contiene los valores de cada argumento de entrada, ordenados por nombre de argumento.When the workflow is invoked, the arguments dictionary is passed which contains the values for each input argument, keyed by argument name. Cuando la llamada a Invoke devuelve resultados, cada uno de los argumentos de salida se devuelve en el diccionario outputs, ordenados por nombre de argumento.When the call to Invoke returns, each output argument is returned in the outputs dictionary, also keyed by argument name.

public sealed class Divide : CodeActivity
{
    [RequiredArgument]
    public InArgument<int> Dividend { get; set; }

    [RequiredArgument]
    public InArgument<int> Divisor { get; set; }

    public OutArgument<int> Remainder { get; set; }
    public OutArgument<int> Result { get; set; }

    protected override void Execute(CodeActivityContext context)
    {
        int quotient = Dividend.Get(context) / Divisor.Get(context);
        int remainder = Dividend.Get(context) % Divisor.Get(context);

        Result.Set(context, quotient);
        Remainder.Set(context, remainder);
    }
}
int dividend = 500;
int divisor = 36;

Dictionary<string, object> arguments = new Dictionary<string, object>();
arguments.Add("Dividend", dividend);
arguments.Add("Divisor", divisor);

IDictionary<string, object> outputs =
    WorkflowInvoker.Invoke(new Divide(), arguments);

Console.WriteLine("{0} / {1} = {2} Remainder {3}",
    dividend, divisor, outputs["Result"], outputs["Remainder"]);

Si el flujo de trabajo se deriva de ActivityWithResult, como CodeActivity<TResult> o Activity<TResult>, y hay argumentos de salida, además del argumento de salida Result bien determinado, se debe utilizar una sobrecarga no genérica de Invoke para recuperar argumentos adicionales.If the workflow derives from ActivityWithResult, such as CodeActivity<TResult> or Activity<TResult>, and there are output arguments in addition to the well-defined Result output argument, a non-generic overload of Invoke must be used in order to retrieve the additional arguments. Para ello, la definición de flujo de trabajo pasada a Invoke debe ser de tipo Activity.To do this, the workflow definition passed into Invoke must be of type Activity. En este ejemplo la actividad Divide se deriva de CodeActivity<int>, pero se declara como Activity para utilizar una sobrecarga no genérica de Invoke que devuelve un diccionario de argumentos en lugar de un valor único.In this example the Divide activity derives from CodeActivity<int>, but is declared as Activity so that a non-generic overload of Invoke is used which returns a dictionary of arguments instead of a single return value.

public sealed class Divide : CodeActivity<int>
{
    public InArgument<int> Dividend { get; set; }
    public InArgument<int> Divisor { get; set; }
    public OutArgument<int> Remainder { get; set; }

    protected override int Execute(CodeActivityContext context)
    {
        int quotient = Dividend.Get(context) / Divisor.Get(context);
        int remainder = Dividend.Get(context) % Divisor.Get(context);

        Remainder.Set(context, remainder);

        return quotient;
    }
}
int dividend = 500;
int divisor = 36;

Dictionary<string, object> arguments = new Dictionary<string, object>();
arguments.Add("Dividend", dividend);
arguments.Add("Divisor", divisor);

Activity wf = new Divide();

IDictionary<string, object> outputs =
    WorkflowInvoker.Invoke(wf, arguments);

Console.WriteLine("{0} / {1} = {2} Remainder {3}",
    dividend, divisor, outputs["Result"], outputs["Remainder"]);

Usar WorkflowApplicationUsing WorkflowApplication

WorkflowApplication proporciona un amplio conjunto de características para la administración de instancias de flujo de trabajo.WorkflowApplication provides a rich set of features for workflow instance management. WorkflowApplication actúa como un proxy seguro para subprocesos para la WorkflowInstance real, que encapsula el tiempo de ejecución y proporciona métodos para crear y cargar las instancias de flujo de trabajo, pausar y reanudar, terminar y notificar los eventos de ciclo de vida.WorkflowApplication acts as a thread safe proxy to the actual WorkflowInstance, which encapsulates the runtime, and provides methods for creating and loading workflow instances, pausing and resuming, terminating, and notification of lifecycle events. Para ejecutar un flujo de trabajo mediante WorkflowApplication, cree WorkflowApplication, suscríbase a cualquier evento de ciclo de vida que desee, inicie el flujo de trabajo y, a continuación, espere a que termine.To run a workflow using WorkflowApplication you create the WorkflowApplication, subscribe to any desired lifecycle events, start the workflow, and then wait for it to finish. En este ejemplo, se crea una definición de flujo de trabajo que consta de una actividad WriteLine y se crea una WorkflowApplication usando la definición de flujo de trabajo especificada.In this example, a workflow definition that consists of a WriteLine activity is created and a WorkflowApplication is created using the specified workflow definition. Se controla Completed de forma que se notifica al host cuando el flujo de trabajo se completa, el flujo de trabajo se inicia con una llamada a Run y el host espera a que el flujo de trabajo se complete.Completed is handled so the host is notified when the workflow completes, the workflow is started with a call to Run, and then the host waits for the workflow to complete. Cuando se completa el flujo de trabajo, se establece AutoResetEvent y la aplicación host puede reanudar la ejecución, tal y como se muestra en el siguiente ejemplo.When the workflow completes, the AutoResetEvent is set and the host application can resume execution, as shown in the following example.

AutoResetEvent syncEvent = new AutoResetEvent(false);

Activity wf = new WriteLine
{
    Text = "Hello World."
};

// Create the WorkflowApplication using the desired
// workflow definition.
WorkflowApplication wfApp = new WorkflowApplication(wf);

// Handle the desired lifecycle events.
wfApp.Completed = delegate(WorkflowApplicationCompletedEventArgs e)
{
    syncEvent.Set();
};

// Start the workflow.
wfApp.Run();

// Wait for Completed to arrive and signal that
// the workflow is complete.
syncEvent.WaitOne();

Eventos de ciclo de vida de WorkflowApplicationWorkflowApplication Lifecycle Events

Además de Completed, se puede notificar a los autores de hosts cuando se descargue un flujo de trabajo (Unloaded), se anule (Aborted), se vuelva inactivo (Idle y PersistableIdle) o se produzca una excepción no controlada (OnUnhandledException).In addition to Completed, host authors can be notified when a workflow is unloaded (Unloaded), aborted (Aborted), becomes idle (Idle and PersistableIdle), or an unhandled exception occurs (OnUnhandledException). Los desarrolladores de aplicaciones de flujo de trabajo pueden administrar estas notificaciones y realizar la acción adecuada, tal y como se muestra en el siguiente ejemplo.Workflow application developers can handle these notifications and take appropriate action, as shown in the following example.

wfApp.Completed = delegate(WorkflowApplicationCompletedEventArgs e)
{
    if (e.CompletionState == ActivityInstanceState.Faulted)
    {
        Console.WriteLine("Workflow {0} Terminated.", e.InstanceId);
        Console.WriteLine("Exception: {0}\n{1}",
            e.TerminationException.GetType().FullName,
            e.TerminationException.Message);
    }
    else if (e.CompletionState == ActivityInstanceState.Canceled)
    {
        Console.WriteLine("Workflow {0} Canceled.", e.InstanceId);
    }
    else
    {
        Console.WriteLine("Workflow {0} Completed.", e.InstanceId);

        // Outputs can be retrieved from the Outputs dictionary,
        // keyed by argument name.
        // Console.WriteLine("The winner is {0}.", e.Outputs["Winner"]);
    }
};

wfApp.Aborted = delegate(WorkflowApplicationAbortedEventArgs e)
{
    // Display the exception that caused the workflow
    // to abort.
    Console.WriteLine("Workflow {0} Aborted.", e.InstanceId);
    Console.WriteLine("Exception: {0}\n{1}",
        e.Reason.GetType().FullName,
        e.Reason.Message);
};

wfApp.Idle = delegate(WorkflowApplicationIdleEventArgs e)
{
    // Perform any processing that should occur
    // when a workflow goes idle. If the workflow can persist,
    // both Idle and PersistableIdle are called in that order.
    Console.WriteLine("Workflow {0} Idle.", e.InstanceId);
};

wfApp.PersistableIdle = delegate(WorkflowApplicationIdleEventArgs e)
{
    // Instruct the runtime to persist and unload the workflow.
    // Choices are None, Persist, and Unload.
    return PersistableIdleAction.Unload;
};

wfApp.Unloaded = delegate(WorkflowApplicationEventArgs e)
{
    Console.WriteLine("Workflow {0} Unloaded.", e.InstanceId);
};

wfApp.OnUnhandledException = delegate(WorkflowApplicationUnhandledExceptionEventArgs e)
{
    // Display the unhandled exception.
    Console.WriteLine("OnUnhandledException in Workflow {0}\n{1}",
        e.InstanceId, e.UnhandledException.Message);

    Console.WriteLine("ExceptionSource: {0} - {1}",
        e.ExceptionSource.DisplayName, e.ExceptionSourceInstanceId);

    // Instruct the runtime to terminate the workflow.
    // Other choices are Abort and Cancel. Terminate
    // is the default if no OnUnhandledException handler
    // is present.
    return UnhandledExceptionAction.Terminate;
};

Definir argumentos de entrada de un flujo de trabajoSetting Input Arguments of a Workflow

Se pueden pasar datos a un flujo de trabajo cuando se inicia gracias a un diccionario de parámetros, al igual que la manera en que los datos se pasan cuando se usa WorkflowInvoker.Data can be passed into a workflow as it is started using a dictionary of parameters, similar to the way data is passed in when using WorkflowInvoker. Cada elemento en el diccionario se asigna a un argumento de entrada del flujo de trabajo especificado.Each item in the dictionary maps to an input argument of the specified workflow. En este ejemplo, se invoca un flujo de trabajo que está compuesto de una actividad WriteLine y se especifica su argumento Text mediante el diccionario de parámetros de entrada.In this example, a workflow that consists of a WriteLine activity is invoked and its Text argument is specified using the dictionary of input parameters.

AutoResetEvent syncEvent = new AutoResetEvent(false);

Activity wf = new WriteLine();

// Create the dictionary of input parameters.
Dictionary<string, object> inputs = new Dictionary<string, object>();
inputs.Add("Text", "Hello World!");

// Create the WorkflowApplication using the desired
// workflow definition and dictionary of input parameters.
WorkflowApplication wfApp = new WorkflowApplication(wf, inputs);

// Handle the desired lifecycle events.
wfApp.Completed = delegate(WorkflowApplicationCompletedEventArgs e)
{
    syncEvent.Set();
};

// Start the workflow.
wfApp.Run();

// Wait for Completed to arrive and signal that
// the workflow is complete.
syncEvent.WaitOne();

Recuperar argumentos de salida de un flujo de trabajoRetrieving Output Arguments of a Workflow

Cuando un flujo de trabajo se completa, se puede recuperar cualquier parámetro de salida en el controlador Completed teniendo acceso al diccionario WorkflowApplicationCompletedEventArgs.Outputs.When a workflow completes, any output arguments can be retrieved in the Completed handler by accessing the WorkflowApplicationCompletedEventArgs.Outputs dictionary. En el siguiente ejemplo, se hospeda un flujo de trabajo utilizando WorkflowApplication.The following example hosts a workflow using WorkflowApplication. Una WorkflowApplication instancia de se construye utilizando una definición de flujo de trabajo que DiceRoll consta de una sola actividad.A WorkflowApplication instance is constructed using a workflow definition consisting of a single DiceRoll activity. La actividad DiceRoll tiene dos argumentos de salida que representan los resultados de la operación de tirar los dados.The DiceRoll activity has two output arguments that represent the results of the dice roll operation. Cuando se completa el flujo de trabajo, las salidas se recuperan en el controlador Completed.When the workflow completes, the outputs are retrieved in the Completed handler.

public sealed class DiceRoll : CodeActivity
{
    public OutArgument<int> D1 { get; set; }
    public OutArgument<int> D2 { get; set; }

    static Random r = new Random();

    protected override void Execute(CodeActivityContext context)
    {
        D1.Set(context, r.Next(1, 7));
        D2.Set(context, r.Next(1, 7));
    }
}
 // Create a WorkflowApplication instance.
 WorkflowApplication wfApp = new WorkflowApplication(new DiceRoll());

 // Subscribe to any desired workflow lifecycle events.
 wfApp.Completed = delegate(WorkflowApplicationCompletedEventArgs e)
 {
     if (e.CompletionState == ActivityInstanceState.Faulted)
     {
         Console.WriteLine("Workflow {0} Terminated.", e.InstanceId);
         Console.WriteLine("Exception: {0}\n{1}",
             e.TerminationException.GetType().FullName,
             e.TerminationException.Message);
     }
     else if (e.CompletionState == ActivityInstanceState.Canceled)
     {
         Console.WriteLine("Workflow {0} Canceled.", e.InstanceId);
     }
     else
     {
         Console.WriteLine("Workflow {0} Completed.", e.InstanceId);

         // Outputs can be retrieved from the Outputs dictionary,
         // keyed by argument name.
         Console.WriteLine("The two dice are {0} and {1}.",
             e.Outputs["D1"], e.Outputs["D2"]);
     }
 };

// Run the workflow.
 wfApp.Run();

Nota

WorkflowApplication y WorkflowInvoker toman un diccionario de argumentos de entrada y devuelven un diccionario de argumentos out.WorkflowApplication and WorkflowInvoker take a dictionary of input arguments and return a dictionary of out arguments. Estos parámetros, propiedades y valores devueltos del diccionario son del tipo IDictionary<string, object>.These dictionary parameters, properties, and return values are of type IDictionary<string, object>. La instancia real de la clase de diccionario que se pasa puede ser cualquier clase que implemente IDictionary<string, object>.The actual instance of the dictionary class that is passed in can be any class that implements IDictionary<string, object>. En estos ejemplos, se usa Dictionary<string, object>.In these examples, Dictionary<string, object> is used. Para obtener más información acerca de los IDictionary<TKey,TValue> diccionarios Dictionary<TKey,TValue>, vea y.For more information about dictionaries, see IDictionary<TKey,TValue> and Dictionary<TKey,TValue>.

Pasar datos en un flujo de trabajo en ejecución mediante marcadoresPassing Data into a Running Workflow Using Bookmarks

Los marcadores son el mecanismo por el que una actividad puede esperar de forma pasiva a que se reanude y, además, un mecanismo para pasar los datos a una instancia de flujo de trabajo en ejecución.Bookmarks are the mechanism by which an activity can passively wait to be resumed and are a mechanism for passing data into a running workflow instance. Si una actividad está esperando los datos, puede crear Bookmark y registrar un método de devolución de llamada que se va a llamar cuando se reanude Bookmark, tal y como se muestra en el siguiente ejemplo.If an activity is waiting for data, it can create a Bookmark and register a callback method to be called when the Bookmark is resumed, as shown in the following example.

public sealed class ReadLine : NativeActivity<string>
{
    [RequiredArgument]
    public InArgument<string> BookmarkName { get; set; }

    protected override void Execute(NativeActivityContext context)
    {
        // Create a Bookmark and wait for it to be resumed.
        context.CreateBookmark(BookmarkName.Get(context),
            new BookmarkCallback(OnResumeBookmark));
    }

    // NativeActivity derived activities that do asynchronous operations by calling 
    // one of the CreateBookmark overloads defined on System.Activities.NativeActivityContext 
    // must override the CanInduceIdle property and return true.
    protected override bool CanInduceIdle
    {
        get { return true; }
    }

    public void OnResumeBookmark(NativeActivityContext context, Bookmark bookmark, object obj)
    {
        // When the Bookmark is resumed, assign its value to
        // the Result argument.
        Result.Set(context, (string)obj);
    }

Cuando se ejecuta, la actividad ReadLine crea un Bookmark, registra una devolución de llamada y, a continuación, espera a que se reanude Bookmark.When executed, the ReadLine activity creates a Bookmark, registers a callback, and then waits for the Bookmark to be resumed. Cuando lo haga, la actividad ReadLine asigna los datos que se pasaron con Bookmark a su argumento Result.When it is resumed, the ReadLine activity assigns the data that was passed with the Bookmark to its Result argument. En este ejemplo, se crea un flujo de trabajo que usa la actividad ReadLine para recopilar el nombre del usuario y mostrarlo en la ventana de la consola.In this example, a workflow is created that uses the ReadLine activity to gather the user’s name and display it to the console window.

Variable<string> name = new Variable<string>();

Activity wf = new Sequence
{
    Variables = { name },
    Activities =
     {
         new WriteLine
         {
             Text = "What is your name?"
         },
         new ReadLine
         {
             BookmarkName = "UserName",
             Result = new OutArgument<string>(name)

         },
         new WriteLine
         {
             Text = new InArgument<string>((env) => 
                 ("Hello, " + name.Get(env)))
         }
     }
};

// Create a WorkflowApplication instance.
WorkflowApplication wfApp = new WorkflowApplication(wf);

// Workflow lifecycle events omitted except idle.
AutoResetEvent idleEvent = new AutoResetEvent(false);

wfApp.Idle = delegate(WorkflowApplicationIdleEventArgs e)
{
    idleEvent.Set();
};

// Run the workflow.
wfApp.Run();

// Wait for the workflow to go idle before gathering
// the user's input.
idleEvent.WaitOne();

// Gather the user's input and resume the bookmark.
// Bookmark resumption only occurs when the workflow
// is idle. If a call to ResumeBookmark is made and the workflow
// is not idle, ResumeBookmark blocks until the workflow becomes
// idle before resuming the bookmark.
BookmarkResumptionResult result = wfApp.ResumeBookmark("UserName", 
    Console.ReadLine());

// Possible BookmarkResumptionResult values:
// Success, NotFound, or NotReady
Console.WriteLine("BookmarkResumptionResult: {0}", result);

Cuando se ejecuta la actividad ReadLine, crea un Bookmark denominado UserName y, a continuación, espera a que se reanude el marcador.When the ReadLine activity is executed, it creates a Bookmark named UserName and then waits for the bookmark to be resumed. El host recopila los datos deseados y, a continuación, reanuda Bookmark.The host collects the desired data and then resumes the Bookmark. El flujo de trabajo se reanuda, muestra el nombre y, a continuación, finaliza.The workflow resumes, displays the name, and then completes.

La aplicación host puede inspeccionar el flujo de trabajo para determinar si hay marcadores activos.The host application can inspect the workflow to determine if there are any active bookmarks. Puede hacerlo llamando al método GetBookmarks de una instancia WorkflowApplication o inspeccionando el objeto WorkflowApplicationIdleEventArgs en el controlador Idle.It can do this by calling the GetBookmarks method of a WorkflowApplication instance, or by inspecting the WorkflowApplicationIdleEventArgs in the Idle handler.

El siguiente ejemplo de código es similar al ejemplo anterior salvo que los marcadores activos se enumeran antes de que se reanude el marcador.The following code example is like the previous example except that the active bookmarks are enumerated before the bookmark is resumed. Se inicia el flujo de trabajo, y una vez se ha creado el objeto Bookmark y se ha quedado inactivo el flujo de trabajo, se llama al método GetBookmarks.The workflow is started, and once the Bookmark is created and the workflow goes idle, GetBookmarks is called. Cuando se completa el flujo de trabajo, se muestra la siguiente salida en la consola.When the workflow is completed, the following output is displayed to the console.

¿Cómo te llamas?What is your name?
BookmarkName Nombre de usuario-OwnerDisplayName: ReadLine BookmarkName: UserName - OwnerDisplayName: ReadLine
Steve Steve
Hola, SteveHello, Steve

Variable<string> name = new Variable<string>();

Activity wf = new Sequence
{
    Variables = { name },
    Activities =
     {
         new WriteLine
         {
             Text = "What is your name?"
         },
         new ReadLine
         {
             BookmarkName = "UserName",
             Result = new OutArgument<string>(name)

         },
         new WriteLine
         {
             Text = new InArgument<string>((env) => 
                 ("Hello, " + name.Get(env)))
         }
     }
};

// Create a WorkflowApplication instance.
WorkflowApplication wfApp = new WorkflowApplication(wf);

// Workflow lifecycle events omitted except idle.
AutoResetEvent idleEvent = new AutoResetEvent(false);

wfApp.Idle = delegate(WorkflowApplicationIdleEventArgs e)
{
    // You can also inspect the bookmarks from the Idle handler
    // using e.Bookmarks

    idleEvent.Set();
};

// Run the workflow.
wfApp.Run();

// Wait for the workflow to go idle and give it a chance
// to create the Bookmark.
idleEvent.WaitOne();

// Inspect the bookmarks
foreach (BookmarkInfo info in wfApp.GetBookmarks())
{
    Console.WriteLine("BookmarkName: {0} - OwnerDisplayName: {1}",
        info.BookmarkName, info.OwnerDisplayName);
}

// Gather the user's input and resume the bookmark.
wfApp.ResumeBookmark("UserName", Console.ReadLine());

El siguiente ejemplo de código inspecciona el objeto WorkflowApplicationIdleEventArgs pasado al controlador de la propiedad Idle de una instancia de WorkflowApplication.The following code example inspects the WorkflowApplicationIdleEventArgs passed into the Idle handler of a WorkflowApplication instance. En este ejemplo, el flujo de trabajo que va a estar inactivo tiene un objeto Bookmark con el nombre EnterGuess, que una actividad denominada ReadInt posee.In this example the workflow going idle has one Bookmark with a name of EnterGuess, owned by an activity named ReadInt. Este ejemplo de código se basa en cómo: Ejecutar un flujode trabajo, que forma parte del tutorial de introducción.This code example is based off of How to: Run a Workflow, which is part of the Getting Started Tutorial. Si el controlador de la propiedad Idle en ese paso se modifica para contener el código de este ejemplo, se muestra la siguiente salida.If the Idle handler in that step is modified to contain the code from this example, the following output is displayed.

BookmarkName EnterGuess-OwnerDisplayName: ReadIntBookmarkName: EnterGuess - OwnerDisplayName: ReadInt

wfApp.Idle = delegate(WorkflowApplicationIdleEventArgs e)
{
    foreach (BookmarkInfo info in e.Bookmarks)
    {
        Console.WriteLine("BookmarkName: {0} - OwnerDisplayName: {1}",
            info.BookmarkName, info.OwnerDisplayName);
    }

    idleEvent.Set();
};

ResumenSummary

WorkflowInvoker proporciona una manera ligera de invocar los flujos de trabajo y, aunque proporciona los métodos para pasar los datos al principio de un flujo de trabajo y extraer los datos de un flujo de trabajo completado, no se proporciona para escenarios más complejos, que son aquellos en los se puede usar WorkflowApplication.WorkflowInvoker provides a lightweight way to invoke workflows, and although it provides methods for passing data in at the start of a workflow and extracting data from a completed workflow, it does not provide for more complex scenarios which is where WorkflowApplication can be used.