Dynamically Modifying a Workflow from the Outside

In previous post I talked about modifying a running workflow from the inside and stated that there is another option to modify a workflow from the outside which needs more work and code.  In second approach you modify a workflow via workflow runtime.  Here I describe second approach.

To modify a workflow on runtime, you can watch for workflow runtime's WorkflowSuspended event and try to modify your workflow in this event.  To do this, you can use a an AutoResetEvent to suspend workflow runtime then change your workflow and release runtime.

In suspended event you can use a WaitCallback object and delegate of your main method for logic and a WorkflowInstance to pass them to ThreadPool.QueueUserWorkItem() method.

Using the method that you've passed to WaitCallback, it's possible to retrieve a WorkflowInstance and modify it like what you could do to modify from the inside.

Finally you need to release workflow runtime by sending a sign to AutoResetEvent in WorkflowCompleted event of workflow runtime.

Let's apply these theories in an example.

First I change the example of previous post to have a Suspend activity before Delay and Code activities.

Code for delayActivity1 and codeActivity1 is like the past:

private void delayActivity1_InitializeTimeoutDuration(object sender, EventArgs e)

{

    Console.Title = "Modify a Workflow from the Outside Dynamically";

    Console.WriteLine("Delay ...");

}

 

private void codeActivity1_ExecuteCode(object sender, EventArgs e)

{

    CodeActivity delay = sender as CodeActivity;

    Console.WriteLine(delay.Name);

}

Now I use a console application to load my workflow.  In addition to starting this workflow, I'll add two event handlers for my workflow runtime's WorkflowSuspended and WorkflowCompleted events.  Later I'll describe logic for these two handlers.  There is a static AutoResetEvent which will be used globally to suspend workflow.

static AutoResetEvent waitHandle = new AutoResetEvent(false);

 

static void Main(string[] args)

{

    WorkflowRuntime runtime = new WorkflowRuntime();

    runtime.StartRuntime();

 

    runtime.WorkflowSuspended +=

        new EventHandler<WorkflowSuspendedEventArgs>(runtime_WorkflowSuspended);

    runtime.WorkflowCompleted +=

        new EventHandler<WorkflowCompletedEventArgs>(runtime_WorkflowCompleted);

 

    WorkflowInstance instance = runtime.CreateWorkflow(typeof(MyWorkflow));

    instance.Start();

 

    waitHandle.WaitOne();

}

runtime_WorkflowSuspended event handler is where I define a WaitCallback object by passing the address of my main logic method which is named ModifyWorkflow() and must have an Object parameter which keeps WorkflowInstance for runtime.  Here I also retrieve a WorkflowInstance object from runtime then pass that WaitCallback and this WorkflowInstance objects as two parameters to ThreadPool.QueueUserWorkItem() to add my ModifyWorkflow() method to queue of execution methods.

static void runtime_WorkflowSuspended(object sender, WorkflowSuspendedEventArgs e)

{

    WaitCallback waitCallback = new WaitCallback(ModifyWorkflow);

 

    Object workflowState = e.WorkflowInstance;

    ThreadPool.QueueUserWorkItem(waitCallback, workflowState);

}

Now I write ModifyWorkflow() method to implement main logic and add a new Code activity to my workflow (like what I did to modify my workflow from the inside).  Here things are very similar to what I showed for modifying from the inside.  The point is I retrieve a WorkflowInstance object from my ModifyWorkflow() method parameter to add new activity to it and save my changes into it.

static void ModifyWorkflow(Object workflowState)

{

    WorkflowInstance workflowInstance = workflowState as WorkflowInstance;

 

    Activity rootActivity = workflowInstance.GetWorkflowDefinition();

 

    WorkflowChanges workflowChanges = new WorkflowChanges(rootActivity);

 

    CodeActivity codeActivity = new CodeActivity();

    codeActivity.Name = "codeActivity2";

    codeActivity.ExecuteCode += new EventHandler(codeActivity2_ExecuteCode);

 

    workflowChanges.TransientWorkflow.Activities.Add(codeActivity);

 

    workflowInstance.ApplyWorkflowChanges(workflowChanges);

    workflowInstance.Resume();

}

 

static void codeActivity2_ExecuteCode(object sender, EventArgs e)

{

    CodeActivity codeActivity = sender as CodeActivity;

    Console.WriteLine(codeActivity.Name);

    Console.ReadLine();

}

Finally I need to release runtime from suspended mode by calling the Set() method of my AutoResetEvent in runtime_WorkflowCompleted event handler.

static void runtime_WorkflowCompleted(object sender, WorkflowCompletedEventArgs e)

{

    waitHandle.Set();

}

When I run this workflow, will get same output as what I had gotten before.

[advertisement] Axosoft OnTime 2008 is four developer tools in one: bug tracking, project wiki, feature management, and help desk. It manages your development process so developers can focus on coding. Installed or Hosted – Free Single-user license -- Free 30-day team trial.

2 Comments : 12.05.06

Feedbacks

 avatar
#1
DotNetKicks.com
12.05.2006 @ 2:31 PM
You've been kicked (a good thing) - Trackback from DotNetKicks.com
 avatar
#2
Keyvan Nayyeri
06.18.2007 @ 9:00 AM
Back in December 2006, I wrote two posts about dynamically modifying a workflow from the inside and dynamically

Leave a Comment