使用 WorkflowInvoker 和 WorkflowApplicationUsing WorkflowInvoker and WorkflowApplication

Windows Workflow Foundation (WF)提供了几种托管工作流的方法。Windows Workflow Foundation (WF) provides several methods of hosting workflows. WorkflowInvoker 提供一种简单工作流调用方法,就像方法调用一样,仅可用于不使用持久性的工作流。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 为执行工作流(包括生命周期事件通知、执行控制、书签恢复和持久性)提供更丰富的模型。WorkflowApplication provides a richer model for executing workflows that includes notification of lifecycle events, execution control, bookmark resumption, and persistence. WorkflowServiceHost 为消息传递活动提供支持,主要用于工作流服务。WorkflowServiceHost provides support for messaging activities and is primarily used with workflow services. 本主题介绍使用 WorkflowInvokerWorkflowApplication 的工作流承载。This topic introduces you to workflow hosting with WorkflowInvoker and WorkflowApplication. 有关托管工作流的详细信息 WorkflowServiceHost ,请参阅工作流服务承载工作流服务概述For more information about hosting workflows with WorkflowServiceHost, see Workflow Services and Hosting Workflow Services Overview.

使用 WorkflowInvokerUsing WorkflowInvoker

WorkflowInvoker 提供一种执行工作流的模型,如同使用方法调用。WorkflowInvoker provides a model for executing a workflow as if it were a method call. 若要使用 WorkflowInvoker 调用工作流,请调用 Invoke 方法,并传入要调用的工作流的工作流定义。To invoke a workflow using WorkflowInvoker, call the Invoke method and pass in the workflow definition of the workflow to invoke. 在本示例中,使用 WriteLine 调用 WorkflowInvoker 活动。In this example, a WriteLine activity is invoked using WorkflowInvoker.

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

WorkflowInvoker.Invoke(wf);

使用 WorkflowInvoker 调用工作流时,该工作流在调用线程上执行,并且在该工作流完成之前(包括任何空闲时间)会阻止 Invoke 方法。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. 若要配置一个工作流必须在其间完成的超时间隔,请使用一个采用 Invoke 参数的 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 this example, a workflow is invoked twice with two different time-out intervals. 第一个工作流完成,但第二个工作流未完成。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);
}

备注

仅在达到超时间隔且工作流在执行期间进入空闲状态时才会引发 TimeoutExceptionThe TimeoutException is only thrown if the time-out interval elapses and the workflow becomes idle during execution. 如果工作流未进入空闲状态,那么完成时间超过指定超时间隔的工作流将会成功完成。A workflow that takes longer than the specified time-out interval to complete completes successfully if the workflow does not become idle.

WorkflowInvoker 还提供了调用方法的异步版本。WorkflowInvoker also provides asynchronous versions of the invoke method. 有关详细信息,请参阅 InvokeAsyncBeginInvokeFor more information, see InvokeAsync and BeginInvoke.

设置工作流的输入自变量Setting Input Arguments of a Workflow

使用输入参数字典可将数据传入工作流,其中自变量名作为键,并映射到工作流的输入自变量。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. 在本示例中,将要调用 WriteLine,并使用输入参数字典指定其 Text 自变量值。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);

检索工作流的输出自变量Retrieving Output Arguments of a Workflow

使用调用 Invoke 所返回的输出字典,可获得工作流的输出形参。The output parameters of a workflow can be obtained using the outputs dictionary that is returned from the call to Invoke. 下面的示例调用一个工作流,该工作流包含有两个输入自变量和两个输出自变量的单个 Divide 活动。The following example invokes a workflow consisting of a single Divide activity that has two input arguments and two output arguments. 调用工作流时,会传递包含每个输入自变量的值的 arguments 字典(由自变量名键控)。When the workflow is invoked, the arguments dictionary is passed which contains the values for each input argument, keyed by argument name. 当对 Invoke 的调用返回时,将在 outputs 字典中返回每个输出参数(也由参数名键控)。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"]);

如果工作流派生自 ActivityWithResult(例如 CodeActivity<TResult>Activity<TResult>),并且除了正确定义的 Result 输出自变量之外还有其他输出自变量,则必须使用 Invoke 的非泛型重载来检索其他自变量。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. 为此,传递给 Invoke 的工作流定义必须为 Activity 类型。To do this, the workflow definition passed into Invoke must be of type Activity. 在此示例中,Divide 活动派生自 CodeActivity<int>,但被声明为 Activity。因此,将使用 Invoke 的非泛型重载,并返回参数字典,而不是单个返回值。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"]);

使用 WorkflowApplicationUsing WorkflowApplication

WorkflowApplication 为工作流实例管理提供了丰富的功能集。WorkflowApplication provides a rich set of features for workflow instance management. WorkflowApplication 承担实际 WorkflowInstance 的线程安全代理任务,可封装运行时,并提供若干方法,用于创建和加载工作流实例、暂停与继续、终止和通知生命周期事件。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. 若要使用 WorkflowApplication 运行工作流,应创建 WorkflowApplication,订阅所需的所有生命周期事件,启动工作流,然后等待其完成。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. 在本示例中,将要创建由 WriteLine 活动组成定义的工作流,并使用指定工作流定义创建 WorkflowApplicationIn this example, a workflow definition that consists of a WriteLine activity is created and a WorkflowApplication is created using the specified workflow definition. 处理 Completed 以便在工作流完成时通知宿主,通过调用 Run 启动工作流,然后宿主等待工作流完成。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. 工作流完成时,设置 AutoResetEvent,并且主机应用程序可以继续执行,如下例所示。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();

WorkflowApplication 生命周期事件WorkflowApplication Lifecycle Events

除了 Completed,当卸载工作流(Unloaded)、中止工作流(Aborted)、工作流变空闲(IdlePersistableIdle)或产生未经处理的异常(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). 工作流应用程序开发人员可处理这些通知,并执行适当的操作,如下例所示。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;
};

设置工作流的输入自变量Setting Input Arguments of a Workflow

启动工作流时可使用形参字典将数据传入工作流,这与使用 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. 字典中的每一项都映射到指定工作流的一个输入自变量。Each item in the dictionary maps to an input argument of the specified workflow. 在本示例中,将要调用由 WriteLine 活动组成的工作流,并使用输入参数字典指定其 Text 自变量。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();

检索工作流的输出自变量Retrieving Output Arguments of a Workflow

当工作流完成时,可通过访问 Completed 字典在 WorkflowApplicationCompletedEventArgs.Outputs 处理程序中检索任何输出自变量。When a workflow completes, any output arguments can be retrieved in the Completed handler by accessing the WorkflowApplicationCompletedEventArgs.Outputs dictionary. 下面的示例使用 WorkflowApplication 承载一个工作流。The following example hosts a workflow using WorkflowApplication. WorkflowApplication实例是使用由单个活动组成的工作流定义构造的 DiceRollA WorkflowApplication instance is constructed using a workflow definition consisting of a single DiceRoll activity. DiceRoll 活动包含两个表示掷骰子操作结果的输出自变量。The DiceRoll activity has two output arguments that represent the results of the dice roll operation. 当工作流完成时,将在 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();

备注

WorkflowApplicationWorkflowInvoker 采用输入自变量字典,并返回 out 自变量的字典。WorkflowApplication and WorkflowInvoker take a dictionary of input arguments and return a dictionary of out arguments. 这些字典形参、属性及返回值的类型为 IDictionary<string, object>These dictionary parameters, properties, and return values are of type IDictionary<string, object>. 传入的字典类的实际实例可以是实现了 IDictionary<string, object> 的任何类。The actual instance of the dictionary class that is passed in can be any class that implements IDictionary<string, object>. 在这些示例中使用了 Dictionary<string, object>In these examples, Dictionary<string, object> is used. 有关字典的详细信息,请参阅 IDictionary<TKey,TValue>Dictionary<TKey,TValue>For more information about dictionaries, see IDictionary<TKey,TValue> and Dictionary<TKey,TValue>.

使用书签将数据传入运行中的工作流Passing Data into a Running Workflow Using Bookmarks

书签是使活动能够被动等待继续的机制,也是将数据传入运行中的工作流实例的机制。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. 如果某个活动在等待数据,它可以创建 Bookmark,并注册一个在继续 Bookmark 时要调用的回调方法,如下例所示。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);
    }

执行时,ReadLine 活动创建 Bookmark,注册回调,然后等待 Bookmark 继续。When executed, the ReadLine activity creates a Bookmark, registers a callback, and then waits for the Bookmark to be resumed. 继续后,ReadLine 活动将随 Bookmark 传递的数据赋给其 Result 实参。When it is resumed, the ReadLine activity assigns the data that was passed with the Bookmark to its Result argument. 在本示例中,将要创建一个工作流,该工作流使用 ReadLine 活动来收集用户名称并将其显示在控制台窗口中。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);

执行 ReadLine 活动时,该活动创建一个名为 BookmarkUserName,然后等待书签继续。When the ReadLine activity is executed, it creates a Bookmark named UserName and then waits for the bookmark to be resumed. 宿主收集所需的数据,然后继续 BookmarkThe host collects the desired data and then resumes the Bookmark. 工作流继续,显示该名称,然后完成。The workflow resumes, displays the name, and then completes.

主机应用程序可以检查工作流,以确定其中是否存在任何活动书签。The host application can inspect the workflow to determine if there are any active bookmarks. 这可以通过以下方式来完成:调用 GetBookmarks 实例的 WorkflowApplication 方法,或者,在 WorkflowApplicationIdleEventArgs 处理程序中检查 IdleIt can do this by calling the GetBookmarks method of a WorkflowApplication instance, or by inspecting the WorkflowApplicationIdleEventArgs in the Idle handler.

下面的代码示例与前一个示例类似,但在继续书签之前会枚举活动书签。The following code example is like the previous example except that the active bookmarks are enumerated before the bookmark is resumed. 该示例启动工作流,一旦创建了 Bookmark 并且工作流进入空闲状态,就调用 GetBookmarksThe workflow is started, and once the Bookmark is created and the workflow goes idle, GetBookmarks is called. 完成工作流时,会向控制台显示以下输出。When the workflow is completed, the following output is displayed to the console.

你叫什么名字?What is your name?
BookmarkName:用户名-OwnerDisplayName: ReadLine Steve 你好,SteveBookmarkName: UserName - OwnerDisplayName: ReadLine Steve Hello, 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());

下面的代码示例检查传递给 WorkflowApplicationIdleEventArgs 实例的 Idle 处理程序的 WorkflowApplicationThe following code example inspects the WorkflowApplicationIdleEventArgs passed into the Idle handler of a WorkflowApplication instance. 在此示例中,进入空闲状态的工作流包含一个由名为 Bookmark 的活动所拥有的名为 EnterGuessReadIntIn this example the workflow going idle has one Bookmark with a name of EnterGuess, owned by an activity named ReadInt. 此代码示例基于如何:运行工作流,该工作流入门教程的一部分。This code example is based off of How to: Run a Workflow, which is part of the Getting Started Tutorial. 如果修改了该阶段中的 Idle 处理程序以包含此示例中的代码,则将显示以下输出。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();
};

摘要Summary

WorkflowInvoker 提供了一个简便的方法来调用工作流,尽管提供了在工作流开始时传入数据以及从完成的工作流中提取数据的方法,但不提供使用 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.