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: ,

Comments

# Windows Workflow Foundation

Thursday, August 31, 2006 10:26 AM by ScottGu's Blog

Workflow is one of the new core capabilities (along with WPF aka Avalon and WCF aka Indigo) being added

# WF: Windows Workflow Foundation

Thursday, August 31, 2006 3:08 PM by while(availableTime>0) {

Yeah, I know that&#180;s a strange acronym and that it should be WWF, but what would it be of WWF , then?...

# Workflow dynamic update - Beyond Basics

Thursday, August 31, 2006 3:44 PM by Karim Erradi

First, thanks for your ‘WF - How to make a workflow dynamic?’ blog entries. They are very informative and useful.

I really appreciate if you can help with this urgent question, it is really hindering my project progress. Basically, I am trying the change the Workflow when I get some Tracking Event while the WF is running. Basically I have a custom Tracking Service in the Send(TrackingRecord record) method I am trying to change the running instance but I get this error "Instance operation is not valid on workflow runtime thread"! Could please advice if there is any workaround to force the change of the running Workflow in response to a Tracking Event? My scenario is that want to change the running WF in response to receiving UserTrackingRecord, any help is highly appreciated?
I have tried this:
1) Dynamic changes from the activity's code directly – Works fine! But I does not meet all my requirements. Applying the Dynamic Change from a RuntimeService (e.g., Tracking Service) is simply what need. Take the scenario where some unexpected event occurs (for example one of the Web services to be used later on in the WF is offline), in such an event, an external monitoring agent will inform the Tracking Service (the Tracking service would hold-on to such an event) and when the Currently Executing Activity completes I want to do some dynamic change (could be as simple as adding a Delay Activity in the hope that the Web service to be used in subsequent activities will back online).  Another scenario is simply asking the WF to suspend execution until the current problem is dealt with. Any ideas/hints to achieve this is appreciated?
2) Spawn another thread to apply the dynamic changes to the instance -
Note that I have tried  something like System.Threading.ThreadPool.QueueUserWorkItem(new System.Threading.WaitCallback(myApplyAdaptationMethod), workflowInstance);  However this way (in sequential WF with no delay activity), the dynamic change is  only attempted after the Workflow has completed, which is too late. I need to enforce the dynamic change immediately once I get a Tracking Event (or some external event coming from other Monitoring Sources).

I appreciate any guidance with the above.
Thanks
Regards
Karim

# Windows Workflow Foundation

Friday, September 01, 2006 8:44 AM by Tom's corner

# Workflow Foundation Learning - I DID IT!

Saturday, September 16, 2006 11:59 PM by while(availableTime>0) {

Well, today (4th of September 2006, almost the independence day of my country) I decided to learn about...

# Learning Windows Workflow Foundation &laquo; Angel &#8220;Java&#8221; Lopez on Blog

# Aprendiendo Windows Workflow Foundation

Monday, October 09, 2006 11:58 AM by Angel "Java" Lopez

En estos dias, he ordenado algunos enlaces y recursos sobre el Windows Workflow Foundation, el motor

# re: WF - How to make a workflow dynamic? - Part 2

Tuesday, October 24, 2006 11:39 PM by Chris

Thanks for the great information. I do however have 1 question. On a project that we are looking at doing, we are looking at the possibility of using WW (Windows Workflow) along with XML. I know that the WW will allow me to create a workflow as a XAML file. We are wanting to keep several XAMLs in a database and pull them as needed. Do you have an example of how to do this? I have been searching and found out alot, but alot of the examples and things I have played with come close, but not close enough to what I am looking for. Any help would be appreciated. Thanks Chris

# re: WF - How to make a workflow dynamic? - Part 2

Wednesday, October 25, 2006 1:49 AM by bart

Hi Chris, Thanks for reading my blog and the feedback you provide. The scenario you describe is perfectly feasible to do, thanks to the WorkflowCompiler support in WF (which is the abbreviation of Windows Workflow Foundation, instead of WW). I'll try to blog about such a scenario in the foreseeable future (i.e. November). Please contact me at info_at_bartdesmet_dot_net to explain your scenario in more detail. -Bart

# Iulian Tab??r??: Blog &raquo; Blog Archive &raquo; Windows Workflow Foundation

Pingback from  Iulian Tab??r??: Blog  &raquo; Blog Archive   &raquo; Windows Workflow Foundation