Exploring Workflow Foundation Part 3: Running your Custom Activity

In this post I will explore what exactly happens when you’ve added your custom activity to workflow and you execute this workflow.

Loading and executing your custom activity
Activity item = activity.Clone();
Queue queue = new Queue();
The code needed to load and execute you workflow is quite simple:

// Instanciate the workflow runtime
WorkflowRuntime workflowRuntime = new WorkflowRuntime();
//Create a handle to signal the ending og the workflow
AutoResetEvent waitHandle = new AutoResetEvent(false);
// Attach ecventhandlers that signal the workflow ended
workflowRuntime.WorkflowCompleted += 
    delegate(object sender, WorkflowCompletedEventArgs e)
    Console.WriteLine("Workflow completed");
workflowRuntime.WorkflowTerminated += 
    delegate(object sender, WorkflowTerminatedEventArgs e)
// Make a dictionary with the parameters for the activities
//  inside the workflow
Dictionary<String, Object> arguments = new Dictionary<string, object>();
arguments.Add("VariableName", "VariableValue");
// Create the workflow ...
WorkflowInstance instance = workflowRuntime.CreateWorkflow(
                    typeof(WorkflowConsoleApplication.MyWorkflow), arguments);
// ... and execute the workflow
// Wait untill the workflow ended

The actual core code in the above are following three lines:

WorkflowRuntime workflowRuntime = new WorkflowRuntime();
WorkflowInstance instance = workflowRuntime.CreateWorkflow(
                    typeof(WorkflowConsoleApplication.MyWorkflow), arguments);

Now, lets see what happens here…


Following are the steps executed during creation of the workflow:

  • Step 1: Start the runtime if not allready started by:
    • Adding all registered services and some default services needed by the runtime
    • Call the Start method of all these services
    • Call the OnStarted method of all these services
  • Step 2: An internal WorkflowExecutor object is created which will be responsible for executing your workflow.
  • Step 3: A WorkflowInstance object is created
  • Step 4: The WorkflowExecutor object and the WorkflowInstance object are associated with each other
    • Step 4.1: Two instances of the root Activity of your workflow are created, one of which will be effectively executed and the other serving as a template. For this, the latter one is associated with the WorkflowDefinitionProperty of the former.
    • Step 4.2: Hook up more properties and dependency properties
    • Step 4.3: Create a Scheduler object which holds the queue of work to be performed
    • Step 4.4: Create a WorkflowQueuingService
    • Step 4.5: Create a TimerEventsubscriptionCollection
  • Step 5: Call the Initialize method of the root activity in the workflow.
  • Step 6: Return the WorkflowInstance object

Next, we start out WorkflowInstance…


Following are the steps executed during the start method:

  • Step 1: Get the appropriate WorkflowExecutor object for the WorkflowInstance
  • Step 2: Call the WorkflowExecutor’s Start method
    • Step 2.1: Create an ActivityExecutionContext for the WorkflowExecutor’s root activity, which at this point is our workflows root activity
    • Step 2.2: Call the context’s ExecuteActivity method with the same root activity
      • Step 2.2.1: Check if the activity is in the Initilazed state and throw an exception if not
      • Step 2.2.2: Put the activity in the Executing state by calling it’s SetStatus method
      • Step 2.2.3: Schedule the activity for execution which wraps the activity in an ActivityExecutorOperation object and adds this object to the Scheduler queue of activities to execute
      • Step 2.2.4: Report the scheduling back up to the runtime so it can trigger the appropriate events, like WorkflowCompleted, WorkflowTerminated and other.

Handling the queued activities

In the above we analized how activities are added to the work queue, but we didn’t see anyone taking activities from this queue and actually performing the work in the activity.

The act of executing the activites is actually split in two seperate loops:

A first loop is created by the OnStarted method of the DefaultWorkflowSchedulerService. Remember this method was called during creation of our workflow, see Step 1 in WorkflowRuntime.CreateWorkflow. For this, the DefaultWorkflowSchedulerService service requests a thread from the ThreadPool and hands it a method to execute. In this method following steps are executed:

  • Step 1: Get a workitem from the queue of items to perform
  • Step 2: Perform the work

As you can see, nothing much happening here.

The filling of this queue with workitems actually happens during the Start method of the WorkflowExecutor. Steps 2.1 and 2.2 of topic WorkflowInstance.Start, which explain what happens inside the WorkflowExecutor.Start method, are actually wrapped inside a C# using construct.

As every C# developper knows, a using construct wraps the creation of an object and it’s disposal into a code-block:

using (new SomeClass)
    // More code to execute...
} // Dispose method of class SomeClass calles here

Inside the WorkflowExecutor’s Start method, a similar construct with a class named ScheduleWork is made and the Dispose method of this class contains the code that activates the loop resulting in the effective execution of the activities:

  • Step 1: Get an ActivityExecutorOperation to run from the Scheduler
  • Step 2: Run the ActivityExecutorOperation
  • Step 2.1: Get the activity for the ActivityExecutorOperation
  • Step 2.2: If the type of ActivityExecutorOperation is Execute, call the activity’s Execute method


Following is some sample code for executing activities:

The code



Offline Maps: Added automatic URL updating – version 1.4.0

I released version 1.4.0 of the application last weekend.

What’s changed

Not much actually, but I think that what did change will make the application more usefull.

It is now possible to change the base-URL used by the Google Server for obtaining the tiles. Google has the habbit of changing those URL’s quite frequently. And allthough nothing fundamentally changed about how the URL is composed ever changed, it did result in not being able to get the tiles and thus making the applicatio rather useless.

All that has changed now. For those who now how to get at the base-URL (and I will post on how to do this later on), they can just adapt the base-URL used and save the new values.

For those less technical, they can retrieve the latest base-URL from the Offline Maps page on this blog by the click of a button.

Find out how on the Offline Maps page

Enjoy !!!!