Utilizzo di WorkflowInvoker e WorkflowApplicationUsing WorkflowInvoker and WorkflowApplication

Windows Workflow Foundation (WF) fornisce diversi metodi di hosting di flussi di lavoro.Windows Workflow Foundation (WF) provides several methods of hosting workflows. WorkflowInvoker offre un modo semplice per richiamare un flusso di lavoro come se fosse una chiamata a un metodo e può essere usato solo per i flussi di lavoro che non usano la persistenza.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 fornisce un modello più dettagliato per l'esecuzione di flussi di lavoro che include la notifica degli eventi del ciclo di vita, il controllo di esecuzione, la ripresa del segnalibro e la persistenza.WorkflowApplication provides a richer model for executing workflows that includes notification of lifecycle events, execution control, bookmark resumption, and persistence. WorkflowServiceHost fornisce il supporto per le attività di messaggistica e viene principalmente usato con i servizi flusso di lavoro.WorkflowServiceHost provides support for messaging activities and is primarily used with workflow services. In questo argomento viene illustrato l'hosting del flusso di lavoro con WorkflowInvoker e WorkflowApplication.This topic introduces you to workflow hosting with WorkflowInvoker and WorkflowApplication. Per ulteriori informazioni sull'hosting di flussi di lavoro con WorkflowServiceHost, vedere servizi flussi di lavoro e Panoramica di servizi flusso di lavoro che ospita.For more information about hosting workflows with WorkflowServiceHost, see Workflow Services and Hosting Workflow Services Overview.

Uso di WorkflowInvokerUsing WorkflowInvoker

L'oggetto WorkflowInvoker fornisce un modello per l'esecuzione di un flusso di lavoro come se si trattasse di una chiamata al metodo.WorkflowInvoker provides a model for executing a workflow as if it were a method call. Per richiamare un flusso di lavoro tramite l'oggetto WorkflowInvoker, chiamare il metodo Invoke e passare la definizione del flusso di lavoro da richiamare.To invoke a workflow using WorkflowInvoker, call the Invoke method and pass in the workflow definition of the workflow to invoke. In questo esempio viene richiamata un'attività WriteLine tramite l'oggetto WorkflowInvoker.In this example, a WriteLine activity is invoked using WorkflowInvoker.

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

WorkflowInvoker.Invoke(wf);

Quando un flusso di lavoro viene richiamato usando l'oggetto WorkflowInvoker, tale flusso di lavoro viene eseguito sul thread chiamante e il metodo Invoke viene bloccato finché il flusso di lavoro non viene completato, incluso qualsiasi tempo di inattività.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. Per configurare un intervallo di timeout entro cui completare il flusso di lavoro, usare uno degli overload Invoke che accetta un parametro TimeSpan.To configure a time-out interval in which the workflow must complete, use one of the Invoke overloads that takes a TimeSpan parameter. In questo esempio un flusso di lavoro viene richiamato due volte con due intervalli di timeout diversi.In this example, a workflow is invoked twice with two different time-out intervals. Il primo flusso di lavoro viene completato, ma non il secondo.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

L'eccezione TimeoutException viene generata solo se l'intervallo di timeout scade e il flusso di lavoro diventa inattivo durante l'esecuzione.The TimeoutException is only thrown if the time-out interval elapses and the workflow becomes idle during execution. Un flusso di lavoro il cui completamento richiede più tempo rispetto all'intervallo di timeout specificato viene completato correttamente se non diventa inattivo.A workflow that takes longer than the specified time-out interval to complete completes successfully if the workflow does not become idle.

L'elemento WorkflowInvoker fornisce anche versioni asincrone del metodo di richiamo.WorkflowInvoker also provides asynchronous versions of the invoke method. Per altre informazioni, vedere InvokeAsync e BeginInvoke.For more information, see InvokeAsync and BeginInvoke.

Impostazione degli argomenti di input di un flusso di lavoroSetting Input Arguments of a Workflow

I dati possono essere passati in un flusso di lavoro tramite un dizionario di parametri di input, con chiavi in base al nome dell'argomento, che sono mappati agli argomenti di input del flusso di lavoro.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. In questo esempio viene richiamato un oggetto WriteLine e il valore del relativo argomento Text viene specificato usando il dizionario di parametri di input.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);

Recupero degli argomenti di output di un flusso di lavoroRetrieving Output Arguments of a Workflow

I parametri di output di un flusso di lavoro possono essere ottenuti tramite il dizionario di output restituito dalla chiamata all'overload Invoke.The output parameters of a workflow can be obtained using the outputs dictionary that is returned from the call to Invoke. Nell'esempio seguente viene richiamato un flusso di lavoro composto da una singola attività Divide che dispone di due argomenti di input e due di output.The following example invokes a workflow consisting of a single Divide activity that has two input arguments and two output arguments. Quando viene richiamato il flusso di lavoro, viene passato il dizionario arguments che contiene i valori per ogni argomento di input, con chiavi in base al nome dell'argomento.When the workflow is invoked, the arguments dictionary is passed which contains the values for each input argument, keyed by argument name. Quando la chiamata a Invoke restituisce un valore, ogni argomento di output viene restituito nel dizionario outputs, anche con chiavi in base al nome dell'argomento.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"]);

Se il flusso di lavoro deriva da ActivityWithResult, ad esempio CodeActivity<TResult> o Activity<TResult>, ed esistono altri argomenti di output oltre all'argomento di output Result definito correttamente, è necessario usare un overload non generico di Invoke per recuperare gli argomenti aggiuntivi.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. A tale scopo, la definizione del flusso di lavoro passata in Invoke deve essere di tipo Activity.To do this, the workflow definition passed into Invoke must be of type Activity. In questo esempio l'attività Divide deriva da CodeActivity<int>, ma viene dichiarata come Activity in modo che venga usato un overload non generico di Invoke che restituisce un dizionario di argomenti anziché un solo valore restituito.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"]);

Uso di WorkflowApplicationUsing WorkflowApplication

WorkflowApplication offre un'ampia gamma di funzionalità per la gestione delle istanze del flusso di lavoro.WorkflowApplication provides a rich set of features for workflow instance management. WorkflowApplication agisce da proxy thread-safe verso l'oggetto WorkflowInstance effettivo, che incapsula il runtime e fornisce i metodo per creare e caricare istanze del flusso di lavoro, sospendere e riprendere, chiudere e inviare notifiche di eventi del ciclo di vita.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. Per eseguire un flusso di lavoro tramite l'oggetto WorkflowApplication è necessario creare l'oggetto WorkflowApplication, sottoscrivere un qualsiasi evento del ciclo di vita desiderato, avviare il flusso di lavoro, quindi attendere il relativo completamento.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. In questo esempio viene creata una definizione del flusso di lavoro costituita da un'attività WriteLine; con la definizione del flusso specificata viene creato poi un oggetto WorkflowApplication.In this example, a workflow definition that consists of a WriteLine activity is created and a WorkflowApplication is created using the specified workflow definition. L'oggetto Completed viene gestito in modo che all'host sia notificato quando il flusso di lavoro viene completato, il flusso di lavoro viene avviato con una chiamata a Run, quindi l'host attende il completamento del flusso di lavoro.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. Quando il flusso di lavoro viene completato, l'oggetto AutoResetEvent viene impostato e l'applicazione host può riprendere l'esecuzione, come mostrato nell'esempio seguente.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();

Eventi del ciclo di vita di WorkflowApplicationWorkflowApplication Lifecycle Events

Oltre alla proprietà Completed, gli autori di host possono ricevere una notifica quando un flusso di lavoro viene scaricato (Unloaded), interrotto (Aborted), diventa inattivo (Idle e PersistableIdle) o si verifica un'eccezione non gestita (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). Gli sviluppatori di applicazioni del flusso di lavoro possono gestire queste notifiche e intraprendere le azioni appropriate, come mostrato nell'esempio seguente.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;
};

Impostazione degli argomenti di input di un flusso di lavoroSetting Input Arguments of a Workflow

I dati possono essere passati in un flusso di lavoro come se avviati tramite un dizionario di parametri, ovvero in modo simile al passaggio dei dati tramite l'oggetto 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. Ogni elemento del dizionario viene mappato a un argomento di input del flusso di lavoro specificato.Each item in the dictionary maps to an input argument of the specified workflow. In questo esempio viene richiamato un flusso di lavoro costituito da un'attività WriteLine e il relativo argomento Text viene specificato usando il dizionario di parametri di input.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();

Recupero degli argomenti di output di un flusso di lavoroRetrieving Output Arguments of a Workflow

Quando un flusso di lavoro viene completato, qualsiasi argomento di output può essere recuperato nel gestore Completed eseguendo l'accesso al dizionario WorkflowApplicationCompletedEventArgs.Outputs.When a workflow completes, any output arguments can be retrieved in the Completed handler by accessing the WorkflowApplicationCompletedEventArgs.Outputs dictionary. Nell'esempio seguente viene ospitato un flusso di lavoro tramite WorkflowApplication.The following example hosts a workflow using WorkflowApplication. Un'istanza WorkflowApplication viene costruita usando una definizione di flusso di lavoro composta da una singola attività DiceRoll.A WorkflowApplication instance is constructed using using a workflow definition consisting of a single DiceRoll activity. L'attività DiceRoll dispone di due argomenti di output che rappresentano i risultati dell'operazione di lancio dei dadi.The DiceRoll activity has two output arguments that represent the results of the dice roll operation. Quando il flusso di lavoro viene completato, gli output vengono recuperati nel gestore 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

Gli oggetti WorkflowApplication e WorkflowInvoker accettano un dizionario di argomenti di input e restituiscono un dizionario di argomenti out.WorkflowApplication and WorkflowInvoker take a dictionary of input arguments and return a dictionary of out arguments. Questi parametri, proprietà e valori restituiti del dizionario sono di tipo IDictionary<string, object>.These dictionary parameters, properties, and return values are of type IDictionary<string, object>. L'istanza effettiva della classe di dizionario passata può essere qualsiasi classe che implementa IDictionary<string, object>.The actual instance of the dictionary class that is passed in can be any class that implements IDictionary<string, object>. In questi esempi, viene usato Dictionary<string, object>.In these examples, Dictionary<string, object> is used. Per ulteriori informazioni sui dizionari, vedere IDictionary<TKey,TValue> e Dictionary<TKey,TValue>.For more information about dictionaries, see IDictionary<TKey,TValue> and Dictionary<TKey,TValue>.

Passaggio di dati in un flusso di lavoro in esecuzione tramite i segnalibriPassing Data into a Running Workflow Using Bookmarks

I segnalibri consentono a un'attività di attendere passivamente la relativa ripresa, nonché di passare i dati a un'istanza del flusso di lavoro in esecuzione.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. Se un'attività sta attendendo dei dati, può creare un oggetto Bookmark e registrare un metodo callback da chiamare quando l'oggetto Bookmark viene ripreso, come mostrato nell'esempio seguente.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);
    }

In caso di esecuzione, l'attività ReadLine crea un oggetto Bookmark, registra un callback, quindi attende la ripresa dell'oggetto Bookmark.When executed, the ReadLine activity creates a Bookmark, registers a callback, and then waits for the Bookmark to be resumed. Una volta ripresa, l'attività ReadLine assegna i dati passati con l'oggetto Bookmark al relativo argomento Result.When it is resumed, the ReadLine activity assigns the data that was passed with the Bookmark to its Result argument. In questo esempio viene creato un flusso di lavoro che usa l'attività ReadLine per rilevare il nome dell'utente e visualizzarlo nella finestra della console.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);

Quando l'attività ReadLine viene eseguita, crea un oggetto Bookmark denominato UserName e attende la ripresa del segnalibro.When the ReadLine activity is executed, it creates a Bookmark named UserName and then waits for the bookmark to be resumed. L'host raccoglie i dati desiderati, quindi riprende l'oggetto Bookmark.The host collects the desired data and then resumes the Bookmark. Il flusso di lavoro viene ripreso, ne viene visualizzato il nome, quindi viene completato.The workflow resumes, displays the name, and then completes.

L'applicazione host può esaminare il flusso di lavoro per determinare se sono disponibili segnalibri attivi.The host application can inspect the workflow to determine if there are any active bookmarks. Tale operazione può essere eseguita chiamando il metodo GetBookmarks di un'istanza WorkflowApplication o esaminando l'oggetto WorkflowApplicationIdleEventArgs nel gestore Idle.It can do this by calling the GetBookmarks method of a WorkflowApplication instance, or by inspecting the WorkflowApplicationIdleEventArgs in the Idle handler.

L'esempio di codice seguente è simile al precedente, ad eccezione del fatto che i segnalibri attivi vengono enumerati prima che venga ripreso il segnalibro.The following code example is like the previous example except that the active bookmarks are enumerated before the bookmark is resumed. Il flusso di lavoro viene avviato e, una volta creato l'oggetto Bookmark e reso inattivo il flusso di lavoro, viene chiamato il metodo GetBookmarks.The workflow is started, and once the Bookmark is created and the workflow goes idle, GetBookmarks is called. Quando il flusso di lavoro viene completato, l'output seguente viene visualizzato nella console.When the workflow is completed, the following output is displayed to the console.

Come ti chiami?What is your name?
BookmarkName: Nomeutente - OwnerDisplayName: ReadLine BookmarkName: UserName - OwnerDisplayName: ReadLine
Steve Steve
Ciao, 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());

Nell'esempio di codice seguente viene esaminato l'oggetto WorkflowApplicationIdleEventArgs passato nel gestore Idle di un'istanza WorkflowApplication.The following code example inspects the WorkflowApplicationIdleEventArgs passed into the Idle handler of a WorkflowApplication instance. In questo esempio il flusso di lavoro che diventa inattivo dispone di un oggetto Bookmark denominato EnterGuess, di proprietà di un'attività denominata ReadInt.In this example the workflow going idle has one Bookmark with a name of EnterGuess, owned by an activity named ReadInt. Questo esempio di codice è basato su procedura: eseguire un flusso di lavoro, che fa parte del esercitazione introduttiva.This code example is based off of How to: Run a Workflow, which is part of the Getting Started Tutorial. Se il gestore Idle nel passaggio indicato viene modificato per contenere il codice da questo esempio, viene visualizzato l'output seguente.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();
};

RiepilogoSummary

L'oggetto WorkflowInvoker rappresenta un modo semplice per richiamare i flussi di lavoro e, sebbene fornisca i metodi per passare i dati all'inizio di un flusso di lavoro ed estrarli da un flusso di lavoro completato, non garantisce scenari più complessi in cui è possibile usare l'oggetto 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.