Thursday, August 31, 2006 2:00 AM
bart
WF - How to make a workflow dynamic? - Part 2
Introduction
One of the goals of workflows in general is to make "logic", "business processes", etc more visible by having a graphical representation of these. At design time it's pretty easy to compose a workflow using the Visual Studio 2005 designer but to this extent a workflow stays pretty static. So what about adapting or modifying a workflow at runtime? In this series of posts I'll outline various methodologies to modify a running workflow. For part one of this series, take a look over here.
Modification from the outside
In the previous part we've been looking at workflow modification from the inside. One of the problems with such an approach is that the workflow has to be prepared in some way or another to allow changes. That is, code must be present inside the workflow to make the changes. For that reason it might be more interesting in some scenarios to make the change from the ouside. This is what we'll be looking at for now.
Consider the workflow from the previous part again, but now with the first set of activities disabled as shown below. Of course you can just neglect those and create a new empty workflow and add the non-disabled stuff. I just want to point out the powerful "comment out" feature in WF once more :-).

Again we stick with simple CodeActivity activities, this time with the following ExecuteCode definitions:
private void killMeFromOutsideActivity_ExecuteCode(object sender, EventArgs e)
{
Console.WriteLine("I should have been dead by now!");
}
private void HappyEndActivity_ExecuteCode(object sender, EventArgs e)
{
Console.WriteLine("The happy end :-)");
}
In order to change the workflow from the outside we need to reach a (what I use to call) "safe point". Tol illustrate this, I'm showing you the use of a SuspendActivity. Over to the hosting code now:
using(WorkflowRuntime workflowRuntime = new WorkflowRuntime())
{
AutoResetEvent waitHandle = new AutoResetEvent(false);
workflowRuntime.WorkflowCompleted += delegate(object sender, WorkflowCompletedEventArgs e) {waitHandle.Set();};
workflowRuntime.WorkflowTerminated += delegate(object sender, WorkflowTerminatedEventArgs e)
{
Console.WriteLine(e.Exception.Message);
waitHandle.Set();
};
workflowRuntime.WorkflowSuspended += new EventHandler<WorkflowSuspendedEventArgs>(workflowRuntime_WorkflowSuspended);
Dictionary<string, object> arguments = new Dictionary<string, object>();
arguments.Add("AllowUpdates", true);
WorkflowInstance instance = workflowRuntime.CreateWorkflow(typeof(DynamicWf.Workflow1), arguments);
instance.Start();
waitHandle.WaitOne();
}
Most of the code is the same as in part 1. Recall that the AllowUpdates argument is used to determine whether updates are allowed or not by using it inside the workflow's DynamicUpdateCondition Code Condition. So, you can just ignore this for now and in case you're starting from an empty workflow, just ignore this piece of code.
The most important piece of code however is the following:
workflowRuntime.WorkflowSuspended += new EventHandler<WorkflowSuspendedEventArgs>(workflowRuntime_WorkflowSuspended);
with the following corresponding event handler:
static void workflowRuntime_WorkflowSuspended(object sender, WorkflowSuspendedEventArgs e)
{
Console.WriteLine("I'm suspended");
WorkflowInstance workflowInstance = e.WorkflowInstance;
Activity wRoot = workflowInstance.GetWorkflowDefinition();
WorkflowChanges changes = new WorkflowChanges(wRoot);
changes.TransientWorkflow.Activities.Remove(changes.TransientWorkflow.Activities["KillMeFromOutsideActivity"]);
try
{
workflowInstance.ApplyWorkflowChanges(changes);
}
catch (InvalidOperationException ex)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("No update allowed - " + ex.Message);
Console.ResetColor();
}
Console.WriteLine("Let's resume");
e.WorkflowInstance.Resume();
}
The code displayed above should be pretty self-explanatory. Again the WorkflowChanges class is at the center of the update logic. In order to obtain a reference to the running (correction: at this point suspended) workflow we can use the WorkflowSuspendedEventArgs argument's WorkflowInstance property.
Note: An important thing is to call ApplyWorkflowChanges on the workflow object of which the root activity (GetWorkflowDefinition) was passed to the WorkflowChanges constructor. I've run into some troubles when experimenting with this and the code above is the only one which is correct.
The result should look like this:

Again, when making the workflow's DynamicUpdateCondition evaluate to false (see previous episode), as shown below, the update will fail:
Dictionary<string, object> arguments = new Dictionary<string, object>();
arguments.Add("AllowUpdates", false);

Happy WF-ing once again!
Del.icio.us |
Digg It |
Technorati |
Blinklist |
Furl |
reddit |
DotNetKicks
Filed under: Windows Workflow Foundation (WF), .NET Framework 3.0 (WinFX)