Dynamic Update 101 for Windows Workflow Foundation

One of the really cool features of Windows Workflow Foundation is the ability to dynamically update a running workflow by inserting new activities or changing the properties of existing activities. All of this is done at runtime and really opens up some cool possibilities when you start looking at how you could apply this feature. As an example, let's say you created a document review state machine workflow. You have the solution up and running and things are going smoothly. Being the keen observer/architect you are, you added the ability to add/remove different people to/from the review cycle. So, when the time comes that Employee X who was just hired on as an editor needs to be involved in the document reviews that go on, you just dynamically update the workflow and things proceed while you sit back and watch it in action. Ok, so I flourished that example a little, but my point here is to get you thinking about how you can use the Dynamic Update feature in Windows Workflow Foundation and the myriad of possibilities it opens up.

I decided to just create a quick and dirty example on using Dynamic Updates so here goes. To begin with, I created a Sequential Workflow Console Application (one of the project templates supplied with Windows Workflow Foundation). In this workflow, I added a While activity, a Sequence activity inside the While activity, and 2 Code activities inside the Sequence activity. Here's what it looks like:

I then added 2 simple handlers for the 2 Code activities each of which do a simple Console.WriteLine. So, the workflow itself is finished (remember, this is Dynamic Update 101 so I don't want to lose you in a vast oasis of Workflow activities).

Since I started with the Sequential Workflow Console Application, a default host was created for me. When you want to apply dynamic updates to a running workflow, you first need to obtain a WorkflowChanges object. You can do this by simply instantiating that new object passing in the IRootActivity of your already running workflow. So, how do you do this? Simple. When you call the WorkflowRuntime's StartWorkflow method, it returns a WorkflowInstance object. To get the IRootActivity of that instance, just call the GetWorkflowDefintion() method. So, to create a WorkflowChanges object, use (where wfInstance is my WorkflowInstance object):

 WorkflowChanges wfChanges = new WorkflowChanges(wfInstance.GetWorkflowDefinition());

I should mention what's going on here when you do this. If you think about how database transaction work, you obtain the database data, make changes and then apply those changes to complete the transaction. In other words, you obtain a "copy" of the data, make changes on that copy and then once you have made all the changes you commit to update the real data. Windows Workflow Foundation follows the same pattern. When you obtain a WorkflowChanges object, you are really obtaining a copy of the running workflow instance. You can make changes to that workflow until the cows come home (doh! a writer using a cliché) but the changes won't happen on the real instance until you apply them.

Back to our sample. Now that I have a WorkflowChanges object, I can start making some changes. My goal is to insert a new Code activity between the 2 existing code activities. We first have to navigate the workflow's object model to get to our insertion point. Since the 2 existing Code activities (and the Delay) activity are contained within the Sequence activity, we just need to get the Sequence activity. Here's how that's done:

 // drill down to code 2 activity
While whileActivity = wfChanges.TransientWorkflow.Activities["while1"] as While;
Sequence seqActivity = whileActivity.Activities["sequence1"] as Sequence;

Now that we have our target Parent activity, we can create the new Code activity, insert it between the 2 existing Code activities and then save the WorkflowChanges. Creating a new Code activity is a trivial matter. After creating a new instance, add an event handler to the ExecuteCode event. Just like the other Code activities, our code handler will do a simple Console.WriteLine. To insert the activity, you can use the Insert method from the Activities collection of the Sequence activity you obtained above. This method accepts an index denoting where to insert the new activity followed by the activity to insert. Other methods exist for the Activities collection that mirror that of a typical .NET collection (e.g. Add). After that, call the Save method defined on the WorkflowChanges object and apply the changes to the running workflow instance by calling the ApplyWorkflowChanges method from the WorkflowInstance object passing your WorkflowChanges object. Here's the code showing how to do everything just explained:

 // create new code activity to insert
Code newCode = new Code();
newCode.ExecuteCode += new EventHandler(codeActivity_ExecuteCode);

// insert new code activity preceding the code2 activity
seqActivity.Activities.Insert(1, newCode);

// save and apply the workflow changes
wfChanges.Save();

wfInstance.ApplyWorkflowChanges(wfChanges);

There you have it. When you run your project, you should see output similar to the following:

 Executing code block 1
New code block executing
Executing code block 2
Executing code block 1
New code block executing
Executing code block 2
Executing code block 1
New code block executing
Executing code block 2
Executing code block 1
New code block executing
Executing code block 2
Executing code block 1
New code block executing
Executing code block 2
Press any key to continue . . .

As I said, Dynamic Update 101 which is a simple way to enter and start learning this cool feature of Windows Workflow Foundation.

Click here to download the entire project source code

If you have any questions/comments/requests just fire an email off to me.

-Mark