Dynamic Update


Dynamic update is an extremely power feature of Windows Workflow Foundation that directly ties to one of the workflow tenets described in Chapter 1: Workflows are transparent and dynamic throughout their lifecycle, which means that running workflow instances should be flexible enough to have modifiable behavior.

Basically, dynamic update is provided for process scenarios that were not modeled in the workflow during development. Scenarios that might need such functionality are virtually endless. However, situations that might benefit from dynamic update include the following:

  • Skipping specific steps in a workflow by deleting activities

  • Adding additional approval steps in a workflow

  • Modifying numeric thresholds that would allow processes to proceed in special instances

  • Modifying business rules in extraordinary cases

  • Adding an on-hold state to a workflow that requires out-of-band work

Dynamic update is applicable to sequential as well as state-machine workflows. However, when any dynamic changes are made to workflows, they are made to specific instances only, not to the workflow definition itself. It cannot be emphasized enough that dynamic update is to be used in circumstances calling for extraneous behavior that was not modeled by the original workflow developer. If a scenario is likely enough to occur a large percentage of the time, it should probably be added to the workflow definition.

There are many ways you can allow dynamic changes to be made to workflow instances. However, the same classes and patterns are used no matter where these changes are applied in the code. The workflow API provided for dynamic update is described in the following section.

The Dynamic Update API

Most of the classes that assist in the dynamic update process have already been introduced in this book and should be familiar to you. However, there is one class whose sole purpose is to allow dynamic update to occur: WorkflowChanges. This class is in the System.Workflow.ComponentModel name-space. To create an instance of this class, you need to pass a reference to the workflow’s definition class to the constructor. You can easily obtain this reference by calling the GetWorkflowDefinition method of the WorkflowInstance class, as follows:

  WorkflowInstance instance = workflowRuntime.GetWorkflow(instanceId); WorkflowChanges changes = new WorkflowChanges(instance.GetWorkflowDefinition()); 

Now that you have an instance of the WorkflowChanges class, you can start making changes to the workflow definition. To do this, you need to use the workflow definition instance that is exposed in the WorkflowChanges.TransientWorkflow property. TransientWorkflow is of type CompositeActivity, which includes either SequentialWorkflowActivity or StateMachineWorkflowActivity.

To make changes to the workflow’s activity tree, use the Activities property of the reference returned from TransientWorkflow. You can add activities directly to the workflow or as children of other composite activities. For example, you may want to add a new activity to a specific IfElseBranch activity. In addition, you can remove activities by calling the Remove method of the Activities property.

The following code shows an example of how to add an InvokeWorkflowActivity instance that calls another business process to an IfElseBranch activity:

 WorkflowInstance instance = workflowRuntime.GetWorkflow(instanceId); WorkflowChanges changes = new WorkflowChanges(instance.GetWorkflowDefinition()); // create a new InvokeWorkflowActivity instance and set its properties InvokeWorkflowActivity invokeWorkflow = new InvokeWorkflowActivity(); invokeWorkflow.Name = "invokeMyWorkflow"; invokeWorkflow.TargetWorkflow = typeof(MyWorkflow);  // get the transient workflow definition and the IfElseBranch activity of interest CompositeActivity wf = changes.TransientWorkflow; IfElseBranchActivity elseBranch =     wf.Activities["elseBranch"] as IfElseBranchActivity;  // add the InvokeWorkflowActivity instance to the IfElseBranchActivity if (elseBranch != null)     elseBranch.Activities.Add(invokeWorkflow);  // see if there are any errors in the changes we've made ValidationErrorCollection errors = changes.Validate(); if (errors.Count == 0) {     // apply the changes to the workflow instance; we're done!     instance.ApplyWorkflowChanges(changes); } else {     // there were some validation errors, throw an exception     throw new ApplicationException(         "There were errors when updating the workflow!"); } 

The preceding code uses the WorkflowChanges class along with the workflow instance’s Transient Activity property to add the InvokeWorkflowActivity instance to the running workflow. First, the IfElseBranchActivity instance is obtained using its name. Then the new activity is added as a change to the IfElseBranch activity. A call to the Validate method is made to make sure what was just done is legal. Finally, the changes are applied by calling ApplyWorkflowChanges.

Dynamic Update from within the Workflow

So far, the dynamic update examples in this chapter pertained to dynamically changing a running workflow from the context of the workflow runtime’s host. However, there are times when a workflow can anticipate that it may need to change in the future during runtime. In these cases, you can inform a workflow that it is modifying itself.

Changing a workflow from the inside is not that different from doing the same thing from the outside. The biggest difference is that you need to create an instance of the WorkflowChanges class and then apply the changes. When updating workflows from the host, you have to first obtain a reference to a workflow instance you are interested in changing, and then use this reference to create the Workflow Changes instance and call the instance’s ApplyWorkflowChanges method.

Conversely, you do not have access to a WorkflowInstance class internal to a workflow’s definition class. Therefore, the way you create the WorkflowChanges class and apply the changes is slightly different. Consider the following code:

  private void modifyMyself_ExecuteCode(object sender, EventArgs e) {     Console.WriteLine("About to modify myself; look out!");     WorkflowChanges changes = new WorkflowChanges(this);     CompositeActivity workflowCopy = changes.TransientWorkflow;     WhileActivity whileActivity = new WhileActivity("loopStuff");     CodeCondition codeCondition = new CodeCondition();     codeCondition.Condition +=         new EventHandler<ConditionalEventArgs>(codeCondition_Condition);     whileActivity.Condition = codeCondition;     CodeActivity writeStuff = new CodeActivity("writeStuff");     writeStuff.ExecuteCode += new EventHandler(writeStuff_ExecuteCode);     whileActivity.Activities.Add(writeStuff);     workflowCopy.Activities.Add(whileActivity);     this.ApplyWorkflowChanges(changes); } private void codeCondition_Condition(object sender, ConditionalEventArgs e) {     e.Result = i < 5; } private void writeStuff_ExecuteCode(object sender, EventArgs e) {     Console.WriteLine("Index is " + this.i.ToString());     i++; } 

The first difference is that the WorkflowChanges constructor is passed a reference to the workflow definition class itself. Also, the last line of the example calls the ApplyWorkflowChanges method that is originally defined in the CompositeActivity class. In the example covering dynamic update from the host, there is a method of the same name defined on the WorkflowInstance class.

To Update or Not to Update?

Because workflows are all about defining business process and rules, a workflow should be able to accept or reject a set of changes. Just because the client application tells the workflow that it wants to add a new activity to its tree doesn’t mean that performing the change would result in a valid business process. Therefore, the SequentialWorkflowActivity and StateMachineWorkflowActivity classes expose a property called DynamicUpdateCondition that is of type ActivityCondition. (This is in addition to the two other classes that inherit from ActivityCondition, which you learned about previously: CodeCondition and RuleConditionReference.)

Although the DynamicUpdateCondition property is not required to be set for dynamic update to work, its Boolean result dictates whether changes can be applied to a running workflow instance. This is an important property because at certain points during a workflow, changes might disrupt the business process, possibly corrupting data or resulting in an invalid end state. Examples of when you might not want to make changes to the workflow include after an order has already been shipped or before a specific logic branch has been reached in a sequential workflow.

For example, a workflow might want to apply dynamic updates only on odd days of the week (with Sunday being 0, Monday being 1, and so on). To implement this rule, you could set the DynamicUpdate Condition on the workflow with a declarative rule condition. The conditional code would look something like the following:

  (int)System.DateTime.Today.DayOfWeek % 2 == 1 

Figure 11-1 shows the Properties window with this property set.

image from book
Figure 11-1

Now the code in the workflow host needs to attempt an update. The following code tries to create a new CodeActivity instance that writes a message to the console window:

 WorkflowInstance instance = workflowRuntime.GetWorkflow(instanceId); WorkflowChanges changes = new WorkflowChanges(instance.GetWorkflowDefinition()); CodeActivity newCode = new CodeActivity("newCode"); newCode.ExecuteCode += new EventHandler(newCode_ExecuteCode);  CompositeActivity wf = changes.TransientWorkflow;  // this will add the CodeActivity to the end of the workflow wf.Activities.Insert(wf.Activities.Count, newCode);  // apply the changes // if it is an even day of the week, this will throw an exception! instance.ApplyWorkflowChanges(changes); 

The event handler for the new CodeActivity looks like the following:

  static void newCode_ExecuteCode(object sender, EventArgs e) {     Console.WriteLine("From newCode"); } 

If you run this code on a Wednesday, everything works fine, and a From newCode message is displayed. However, if you run it on a Tuesday, you get an InvalidOperationException with a message similar to this: “Workflow changes cannot be applied to instance <your GUID> at this time. The WorkflowChanges condition property on the root activity has evaluated to false.”

Dynamic Update of Rules

In addition to enabling you to make structural changes to workflows instances, the concepts of dynamic update apply to rules. This topic is covered in Chapter 9, so refer to that chapter for more information.



Professional Windows Workflow Foundation
Professional Windows Workflow Foundation
ISBN: 0470053860
EAN: 2147483647
Year: 2004
Pages: 118
Authors: Todd Kitta

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net