Custom Composite using Native Activity
This sample demonstrates how to write a NativeActivity that schedules other Activity objects to control the flow of a workflow’s execution. This sample uses two common control flows, Sequence and While, to demonstrate how to do this.
MySequence, the first thing to notice is that it derives from NativeActivity. NativeActivity is the Activity object that exposes the full breadth of the workflow runtime through the NativeActivityContext passed to the
MySequence exposes a public collection of Activity objects that gets populated by the workflow author. Before the workflow is executed, the workflow runtime calls the CacheMetadata method on each activity in a workflow. During this process, the runtime establishes parent-child relationships for data scoping and lifetime management. The default implementation of the CacheMetadata method uses the TypeDescriptor instance class for the
MySequence activity to add any public property of type Activity or IEnumerable<Activity> as children of the
Whenever an activity exposes a public collection of child activities, it is likely those child activities share state. It is a best practice for the parent activity, in this case
MySequence, to also expose a collection of variables through which the child activities can accomplish this. Like child activities, the CacheMetadata method adds public properties of type Variable or IEnumerable<Variable> as variables associated with the
Besides the public variables, which are manipulated by the children of
MySequence must also keep track of where it is in the execution of its children. It uses a private variable,
currentIndex, to accomplish this. This variable is registered as part of the
MySequence environment by adding a call to the AddImplementationVariable method within the
MySequence activity’s CacheMetadata method. The Activity objects added to the
Activities collection cannot access variables added this way.
MySequence is executed by the runtime, the runtime calls its Execute method, passing in an NativeActivityContext. The NativeActivityContext is the activity’s proxy back into the runtime for dereferencing arguments and variables as well as scheduling other Activity objects, or
MySequence uses an
InternalExecute method to encapsulate the logic of scheduling the first child and all subsequent children in a single method. It starts by dereferencing the
currentIndex. If it is equal to the count in the
Activities collection, then the sequence is finished, the activity returns without scheduling any work and the runtime moves it into the Closed state. If the
currentIndex is less than the count of activities, the next child is obtained from the
Activities collection and
MySequence calls ScheduleActivity, passing in the child to be scheduled and a CompletionCallback that points at the
InternalExecute method. Finally, the
currentIndex is incremented and control is yielded back to the runtime. As long as an instance of
MySequence has a child Activity object scheduled, the runtime considers it to be in the Executing state.
When the child activity completes, the CompletionCallback is executed. The loop continues from the top. Like
Execute, a CompletionCallback takes an NativeActivityContext, giving the implementer access to the runtime.
MyWhile differs from
MySequence in that it schedules a single Activity object repeatedly, and in that it uses a Activity<TResult><bool> named
Condition to determine whether this scheduling should occur. Like
MyWhile uses an
InternalExecute method to centralize its scheduling logic. It schedules the
ConditionActivity<bool> with a CompletionCallback<TResult><bool> named
OnEvaluationCompleted. When the execution of
Condition is completed, its result becomes available through this CompletionCallback in a strongly typed parameter named
MyWhile calls ScheduleActivity, passing in the
BodyActivity object and
InternalExecute as the CompletionCallback. When the execution of
Condition gets scheduled again in
InternalExecute, starting the loop over again. When the
false, an instance of
MyWhile gives control back to the runtime without scheduling the
Body and the runtime moves it to the Closed state.
To set up, build, and run the sample
Open the Composite.sln sample solution in Visual Studio 2010.
Build and run the solution.
The samples may already be installed on your machine. Check for the following (default) directory before continuing.
If this directory does not exist, go to Windows Communication Foundation (WCF) and Windows Workflow Foundation (WF) Samples for .NET Framework 4 to download all Windows Communication Foundation (WCF) and WF samples. This sample is located in the following directory.