Hour 15 Working with Dynamic Update

What You’ll Learn in This Hour:

Image   Dynamic Update overview

Image   Dynamic Update from inside

Image   Dynamic Update from outside

Image   Dynamic Update and rules

Image   Workflow change application

This hour covers Dynamic Update, one of the intriguing features in WF. It permits running workflows to be changed by adding and removing activities. The changes are unique to the workflow instance they are applied to, which permits per order, invoice, or other business transaction customization. Increased flexibility is one of WF’s goals. One way to provide this is to permit already running workflows to be changed. Midprocess change alone, however, is not good enough in many cases. It can lead to chaos. That’s why it is important for the midprocess change to be supported by tracking. With the two coupled, it is possible that new types of versioning and deployments can be supported that are less rigid than compiled code but that still supply solid versioning support.

Furthermore, WF provides a couple of other features that increase Dynamic Update’s plausibility. The first is that WF provides a DynamicUpdateCondition property that can restrict at which points of a process, if any, Dynamic Update is allowed.

Second, the WF validation architecture permits midprocess changes to be validated. In fact, the same validation performed on activities at design time is carried out at runtime when Dynamic Update is applied. The WF validation architecture is covered in Hour 24, “Creating Control Flow Activities Session 2.” The fact that validation is abstracted and therefore equally employable at runtime and design time demonstrates that changing workflows at runtime is central to the WF model and not an afterthought.

Dynamic Update works on both sequential and state machine workflows. It is especially synergistic with state machine workflows because of the autonomous design of states. This state machine design makes it easier to add or remove a step (state) without adversely affecting the process. One scenario that works well on state machine workflows is to add a hold state to a workflow or series of workflows when, for instance, quality problems are discovered.

Image

If you are interested in looking further into how Dynamic Update can be used with state machine workflows, the OrderingStateMachine SDK example provides a good example of adding a state through Dynamic Update. This hour will not cover using Dynamic Update with state machine workflows.

The next section of this hour covers applying Dynamic Update to add and remove activities from running workflows. The following section covers using Dynamic Update to change workflow rules. Finally, a sample application that creatively employs Dynamic Update is explored at a high level.

Applying Dynamic Update: Outside and Inside

You can apply Dynamic Update in two ways: from outside the workflow and from within the workflow. Applying from outside requires a way to communicate, as well as knowledge of the current step of the running workflow instance, whereas applying from within requires design-time knowledge of where (not necessarily what) the changes are to be applied. Both methods are similar, although additional steps and logistics are involved when applying from outside.

The general dynamic update practice is straightforward. First, a copy of the workflow instance to be changed is copied to a clone for manipulation. After the changes are made, the original workflow is overwritten by the clone, thereby updating a running workflow instance. Two types combine to enable Dynamic Update:

Image   First, the WorkflowChanges type contains a TransientWorkflow property that serves as a workspace to hold proposed changes. The TransientWorkflow property is a composite activity collection that represents the cloned workflow instance. The TransientWorkflow property serves as the framework to add activities to, remove activities from, and change rules on.

Image   The WorkflowChanges type contains a Validate method that validates the proposed changes and a Condition property that controls when and if Dynamic Update can be applied to a workflow. As previously mentioned, this Validate method plays a major role in WF’s ability to support performing running workflow change with fidelity.

Image   The second type, the WorkflowInstance, contains helper methods to retrieve a workflow instance, and it requests that the cloned copy replace the workflow instance. It also holds the specific Dynamic Update rules for the given workflow model.

Let’s now add a Delay activity to a workflow from both the inside and the outside.

Applying Dynamic Update from the Inside

Tracking and a call to query the tracking service was added to the host to make it easier to show the changes made by Dynamic Update.

Follow the next steps to apply Dynamic Update from the inside.

1.   Open the DynamicUpdateFromInside solution in the C:SamsWf24hrsHoursHour15DynamicUpdateDynamicUpdateFromInside directory.

2.   Open InsideWorkflow shown in Figure 15.1.

FIGURE 15.1 DynamicUpdateFromInside workflow.

DynamicUpdateFromInside workflow.

3.   Double-click the codeActivityWDynamicUpdate activity and enter the code shown in Listing 15.1 in its handler (which is explained directly following).

LISTING 15.1 Dynamic Update From Inside


                         Console.WriteLine
                                ("Printed from Code activity before Dynamic Update Code activity
at {0}",

                                DateTime.Now.TimeOfDay);

     // use WorkflowChanges class to author dynamic change and pass
     // it a reference to the current Workflow Instance
     WorkflowChanges workflowTochange = new WorkflowChanges(this);

     // Create a new Delay, initialized to 2 seconds
     DelayActivity delayOrder = new DelayActivity();
     delayOrder.Name = "delayOrder";
     delayOrder.TimeoutDuration = new TimeSpan(0, 0, 2);

     // Insert the Delay Activity to the TransientWorkflow collection

     // (the workspace) between the two Code Activities
     workflowTochange.TransientWorkflow.Activities.Insert(1, delayOrder);

     // Replace the original Workflow Instance with the clone
     this.ApplyWorkflowChanges(workflowTochange);


Adding a Delay activity dynamically took four steps:

1.   Pass a workflow definition to the WorkflowChanges type. After changes are made, the updated WorkflowChanges type will replace the current workflow definition.

2.   The Delay activity is programmatically created.

3.   The Delay activity is added to the WorkflowChanges.TransientWorkflow property that contains a modifiable clone of the current workflow. Both the activity to add and its index position on the workflow are passed to the WorkflowChanges.TransientWorkflow.Activities.Insert method.

4.   The changes are applied to the workflow instance. Validation is performed when WorkflowInstance.Applychanges is called, and it will throw an exception if validation fails.

This encapsulates the basic steps to perform dynamic updates from within a workflow. The WorkflowChanges.TransientWorkflow.Activities.Insert method, which permitted us to specify the position of the Delay activity, was used. There are also Add, Remove, Count and other members that facilitate managing the workflow clone or TransientWorkflow collection. No change method exists because activities cannot be changed. To change an activity you must delete the activity that requires change, create a new activity that includes the change, and then update the workflow with the new activity.

Running the DynamicUpdateFromInside Workflow

Follow the next steps to run the workflow.

1.   Run the workflow, and you should see the results shown in Figure 15.2.

FIGURE 15.2 Dynamic Update Workflow from inside results one.

Dynamic Update Workflow from inside results one.

2.   You can tell that the Delay activity was added because the time difference between the start of the first and second Code activities matches the Delay activity TimeoutDuration property. You can also tell because the delayOrder (the name of the Delay activity) is included in the tracking query returned. The tracking database has an AddedActivity and a RemovedActivity table that is populated by Dynamic Update. It theoretically allows for per instance change to be performed with visibility, although this is just an SDK sample that is probably not enterprise-ready.

3.   Now you can override Dynamic Update. Click the workflow designer away from any activity.

4.   Click the DynamicUpdateCondition property, click its drop-down, select Code Condition, enter DynamicCondition, and press Enter. Then enter the following in its handler:

          e.Result = false;

5.   You get an exception because Dynamic Update is no longer allowed on this workflow.

Image

Why the need for Dynamic Update from the inside? One scenario is that some WF hosts are closed (for example, the SharePoint workflow host) and the only way to perform Dynamic Update would be from the inside. In these cases, custom activities (see Hours 2024) could be embedded in the workflow that communicates with external programs that send the update instructions.

You have run the workflow with Dynamic Update where you saw a Delay activity added to a running workflow. Then you changed the Dynamic Update rule to prohibit Dynamic Update, and the change was no longer allowed. The combination of tracking support, conditional evaluation, and activity validation (see Hour 24, “Creating Control Flow Activities Session 2”) incorporated in Dynamic Update makes Dynamic Update very intriguing. Whereas XAML-only workflows can be run without compilation, Dynamic Update takes it a step further and permits change while in-flight on a per-instance basis. With Dynamic Update you can update a single workflow or selected workflow instances. Changing the XAML directly affects all workflows that run from that point.

In the “Applying Dynamic Update from the Outside Unplanned” section, you will conduct an unplanned change from the host. You will not implement a planned change from the host, but how to do so is discussed.

Applying Dynamic Update from the Outside Unplanned

You will now work with a similar workflow. This time, though, you will change from the host (the outside). Scenarios where changing from the host may be useful range from changing one or more in-flight workflows because of new requirements that may range from putting the workflows on hold because of a product defect to meeting new design requirements. Another possibility is changing all workflows from the host when they are started to allow changes to be implemented this way until next time you redeploy the workflow with the changes embedded.

This time, because the changes are from the outside and are unplanned, they are performed when the workflow idles. This will lessen the chance of race conditions, in contrast to simply placing the request on the queue while the workflow is running without consideration to what it is doing. (Workflow queues are covered in Hour 21, “Creating Queued Activities,” and Hour 22, “Creating Typed Queued and EventDriven-Enabled Activities.”)

1.   Open the DynamicUpdateFromOutside solution in the C:SamsWf24hrsHoursHour15DynamicUpdateDynamicUpdateFromOutside directory.

2.   Open the OutsideWorkflow shown in Figure 15.3.

FIGURE 15.3 DynamicUpdateFromOutside workflow.

DynamicUpdateFromOutside workflow.

3.   Now open Program.cs and add the code shown in Listing 15.2 to the OnWorkflowIdled handler, which is explained afterward.

LISTING 15.2 Dynamic Update From Outside Unplanned


          if (wasChanged)
              return; wasChanged = true;

          // Instantiate a Workflow Instance
          WorkflowInstance workflowInstance = e.WorkflowInstance;

          // Static definition of the WF (replacing this when the change
          // is conducted from within.
          Activity clonedWorkflow =
              workflowInstance.GetWorkflowDefinition();

          // use WorkflowChanges class to author dynamic change
          WorkflowChanges workflowChanges =
              new WorkflowChanges(clonedWorkflow);

          Console.WriteLine(" Host is adding a new Delay Activity");

          // Create a new Delay, initialized to 2 seconds
          DelayActivity delayOrder = new DelayActivity();
          delayOrder.Name = "delayOrder";
          delayOrder.TimeoutDuration = new TimeSpan(0, 0, 2);

          // Add the Approval Activity to the collection
          workflowChanges.TransientWorkflow.Activities.Add(delayOrder);

          // apply transient changes to instance
          workflowInstance.ApplyWorkflowChanges(workflowChanges);


First, the variable wasChanged is checked to test whether the update has previously been performed. The OnWorkflowIdled event may be called many times in most real-world workflows, and the Delay activity should be added only once.

Second, it requires an extra step to get the workflow from the host. The WorkflowInstance.GetWorkflowDefintion method returns a clone of the workflow instance. You can’t just refer to the workflow as you can from inside the workflow. This copy is then passed to the WorkflowChanges type. The rest of the code is identical to when performing Dynamic Update from the inside.

Running the DynamicUpdateFromOutside Unplanned

Follow the next steps to run the DynamicUpdateFromOutside unplanned.

1.   Run the workflow, and you should see the results shown in Figure 15.4.

FIGURE 15.4 Dynamic Update Workflow from outside unplanned.

Dynamic Update Workflow from outside unplanned.

2.   This time the delayOrder activity is executed after the codeActivityAfterDynamicUpdate because that’s the way the WF scheduler works. You will learn about scheduling and queuing in the custom activity hours (2024).

Explaining Dynamic Update from the Outside Planned

If you know your process is spontaneous and workflow instances will frequently require change, another approach is to pause the workflow with a Suspend activity at a point of the workflow that you know will (is likely to) require change at design time. Then catch the Suspended event. The advantage is that you know ahead of time where to make the change—if not what change to make—and you don’t have to attempt to capture the workflow at an idle state at the point of the workflow in which you want to make the change. You know that it is stopped, and you know exactly where it is stopped. This method of (know where but not what) Dynamic Update can be useful for processes that contain parts that vary widely across workflows. For instance, maybe the credit-hold process is unique across orders because of all the human intervention, and a template is built for each order that can be changed as needed. In this situation, you may even carve out a section of the workflow after the Suspend activity and place stub activities that you will later change.

There is no example for this because it is so similar to the previous section. The main difference is placing the code in the suspended event handler rather than the idled.

Updating Rules Dynamically

It is important that rules be changeable at runtime because they are frequently the least deterministic element or processes. For instance, an order will go on credit-hold if it exceeds the credit limit. The actual credit limit, who to request approval from, and how many levels to escalate within are all determined by rules. These rules tend to change frequently.

WF RuleSets and declarative rule conditions can both be modified at runtime. The RuleDefinitions type contains a RuleSets property that holds a collection of RuleSets in the workflow and the Conditions property that holds a collection of workflow declarative rule conditions. The RuleDefinitionsProperty is a dependency property known by the workflow. Modifying the rules therefore requires accessing one or both of these properties during Dynamic Update, and then applying the changes to update the current workflow instance with the new values.

You can update the RuleSets and Conditions properties through CodeDom expressions or by updating the .rules file that holds their serialized representation. Updating the CodeDom permits programmatic rules change from the host. The .rules files can be updated directly or via a user interface that updates the .rules files. In a scenario that calls for workflows that continually update rules throughout the workflow life cycle, you could allow the .rules file to be updated from an external application. The host could then check the .rules file at each persistence point and update any changes.

All parts of the rules and corresponding actions can be changed regardless of which change method is selected. For example, all aspects of the rule (OrderValue < 1000 Then OrderPriority = 1) can be changed, including changing OrderValue to OrderValue + Tax or OrderValue to InvoiceAmount. The changes implemented in our examples will be limited to changing the literal values (1000 and 1 in the preceding example) because complex CodeDom programming is not within the scope of this book. However, changing the literal values offers a glimpse into changing other parts of the rule expressions. The ability to change the entire rule without recompilation is clearly a powerful feature that is not easily done in compiled software.

Image

Code conditions can be applied to IfElse, While, and other activities, just as declarative rule conditions can. Code conditions, however, are not captured by the Conditions property and are therefore not changeable at runtime. This again exemplifies that XML representations both (XAML and .rules) are better supported by WF tools in some areas.

The rest of this section provides a sample of changing a RuleSet and Conditions property via the CodeDom and changing a RuleSet property through a .rules file. The workflow shown in Figure 15.5 will be used for all three changes, although the SetPriorityPolicy activity is enabled only when changing the RuleSet rule.

FIGURE 15.5 Dynamic Update rules.

Dynamic Update rules.

Image

A custom Policy activity as covered in Hour 12, “Working with the WF RuleSet,” may be more appropriate to update rules at runtime. For XAML-only workflows, you can simply load the .rules file at runtime if it is sufficient to make the changes when starting the workflow. This allows business users to change the rules until the workflow begins. The rules cannot be modified after the workflow starts processing, however, which may not be sufficient, especially for some long-running workflows. The scope of the intended change is also important when deciding which approach to use. Dynamic Update can be applied to one or a select group of workflows. XAML and custom Policy activities generally apply to all future workflows. The custom Policy activity may also apply to currently processing workflows, depending on its implementation.

Selecting Which Version to Run

Follow the next steps to add code to allow which Dynamic Update scenario to run:

1.   Open the DynamicUpdateRules solution in the C:SamsWf24hrsHoursHour15DynamicUpdateDynamicUpdateRules directory.

2.   Open Program.cs and add the following code below the opening bracket of the using (WorkflowRuntime... line of code. This code allows for choosing which of the Dynamic Update scenarios to execute. It is necessary because only one host is being used for all three types of Dynamic Update that will be processed in this section.

          Console.WriteLine("Enter 1 and press Enter for rule condition,");
          Console.Write("2 for RuleSet rule,");
          Console.Write("3 for .rules file: ");
          selection = Console.ReadLine();
          Console.WriteLine("Choice {0} selected.", selection);
          Console.WriteLine();

Changing Declarative Rule Conditions with Dynamic Update

Now you will employ Dynamic Update to change the rule condition on the left branch of the IfElse activity. The initial value of the rule condition of the left branch is this.orderPriority == 1. The OrderPriority is passed in from the host as 2. Thus, the conditional will evaluate to false and regular shipping will be received. When the workflow reaches the Delay activity, it will persist. The host’s idled handler will be called, where the left branch rule condition will be set to "orderPriority <= 2". The rule will therefore evaluate to true on the next iteration and receive special shipping.

The IfElse activity will execute two times, because it is embedded in a While activity with the following code condition: Counter < 2.

Follow these steps to change a rule with Dynamic Update.

1.   Add the code below the following comment in the Progam.cs Main method: Add Dynamic Update Selection Code here. This code passes in the property parameters to run scenario 1 (change rule condition via CodeDom).

          // Dynamically changing rule condition via CodeDom
          if (selection == "1")
          {
              Console.WriteLine(
                  "Orders with OrderPriority equal to 1 get special
shipping. ");
              Console.WriteLine("(The initial OrderPriority value = 2)."
                     , orderPriority);
              Console.WriteLine();

              parameters.Add("OrderPriority", orderPriority);
          }

2.   Add the following code to the OnWorkflowIdled method. The code you enter over the next few steps will execute when the host idled event is triggered and you select option 1.

               // Change the rule condition on the left-hand branch of the IfEsle
activity
               // from orderPriority == 1 to orderPriority <= 2.
               if (selection == "1" & !wasChanged)
               {
               }

3.   Add the following code within the If {} brackets you entered in the preceding step. The code begins implementing Dynamic Update and is so far no different from what you have done earlier when using Dynamic Update to change the workflow activities and not the rules.

               wasChanged = true;
               Console.WriteLine("Dynamically changing Rule Condition from
Priority = 1 to priority <= 2");

               // Retrieving a workflow instance and cloning it
               WorkflowInstance workflowInstance = e.WorkflowInstance;

               // Dynamic update of order rule
               WorkflowChanges workflowchanges =
                   new WorkflowChanges(workflowInstance.GetWorkflowDefinition());

               CompositeActivity workflowActivityToChange =
                  workflowchanges.TransientWorkflow;

4.   Now we begin with the code specific to changing rules. Add the following code below the code you added in the preceding step. It retrieves the RuleDefinitionsProperty dependency property from the workflow being changed. The RuleDefinitionsProperty holds both the RuleSets and Conditions properties.

               RuleDefinitions ruleDefinitions =
                   (RuleDefinitions)workflowActivityToChange.GetValue
                   (RuleDefinitions.RuleDefinitionsProperty);

5.   Enter the following code below the code you just added to access the Conditions property of the RuleDefinitions property. This will provide you with a collection of all rule conditions in the workflow.

               RuleConditionCollection ruleConditions =
ruleDefinitions.Conditions;

6.   Enter the following code below the code you just added to select the BranchCondition rule condition from the collection of rule conditions and instantiate it as a RuleExpressionCondition. BranchCondition is the name of the rule condition in the left branch of the IfElse activity.

               RuleExpressionCondition conditionBranchCondition =
                   (RuleExpressionCondition)ruleConditions["BranchCondition"];

7.   Enter the following code below the code you just added to change the rule condition via the CodeDom. The conditionBranchCondition instantiated in the previous step is now instantiated as a CodeBinaryOperatorExpression. You have now entered the CodeDom, where the expression will be changed.

               CodeBinaryOperatorExpression expression
                    = conditionBranchCondition.Expression as
CodeBinaryOperatorExpression;

8.   Enter the following code below the code you just added to change the operator of the BranchCondition rule to less than or equal and the value compared to 2. When it is complete, you will have changed the BranchCondition rule condition from orderPriority == 1 to orderPriority <= 2. You can’t see it, but the expression is changed, just as if you entered the second expression yourself.

               expression.Operator = CodeBinaryOperatorType.LessThanOrEqual;
               expression.Right = new CodePrimitiveExpression(2);

9.   Enter the following code below the code you just added to update the changes to the running workflow instance.

               workflowInstance.ApplyWorkflowChanges(workflowchanges);

10.   Run the workflow, enter 1 when prompted, and you should receive the results shown in Figure 15.6. The key is that regular shipping is received on the first iteration and special shipping on the second (the counter is 0-based, so the actual iteration values are 0 and 1).

FIGURE 15.6 Results of running workflow with rule condition dynamically changed in second iteration.

Results of running workflow with rule condition dynamically changed in second iteration.

Image

Be careful when using Dynamic Update to change rules because neither tracking nor tracing shows that a rule has been changed. Both tracking and tracing still work, but the information they display does not tell you that a rule has been changed. This is problematic because changing rules can—and frequently should—alter workflow behavior. This may cause confusion and challenge auditability. For instance, why in a workflow that specifies orderReult == 1, does an order with a value of 2 receive special shipping?

Dynamic rules changes call for clear tracking that shows the rule was changed and what it was changed to. The tracking should also show when the outcome was changed because of Dynamic Update rule changes. There is a Diff method of the RuleDefinitions type that shows the differences between the original rules and the changed rules that could be used to show the differences. You could employ this from the place that Dynamic Update take place. It would still, however, be up to you to get the information to tracking and build other infrastructures. Some of these features may be reserved for Microsoft Rules Engine and BPM products.

Changing a RuleSet Rule via the CodeDom

You can also change all elements of RuleSet rules. In this scenario, you will enable the Policy activity that sets the orderPriority to 1 for orders larger than 100,000 and to 2 for those that are less than 100,000. The OrderAmount is set to 50,000 and passed from the host to the workflow. Therefore, the first run sets the orderPriority to 2. The BranchCondition rule retains its default value (orderPrioroty == 1), causing the workflow to select the right branch of the IfElse activity and to supply regular shipping. When the workflow persists, the idled handler changes the RuleSet rule to set the priority to 1 for orders with an orderAmount > 25,000. This then produces special shipping on the second iteration.

1.   If it is not already enabled, in the Workflow Designer, enable the SetOrderPriority activity.

2.   Add the code shown in Listing 15.3 to the Program.cs Main method below the ending bracket of the if (selection == "1") if statement. This passes the proper parameters to run scenario 2 (change RuleSet rule via CodeDom).

LISTING 15.3 Changing a Rule in a .rules File with Dynamic Update


               // Dynamically changing RuleSet rule condition via CodeDom
               if (selection == "2")
               {
                  Console.WriteLine(
                     "The OrderPriority is set to 1 for Orders>100,000. This earns them
special shipping.");
                    Console.Write("(The intitial OrderAmount value = $50,000)."
                         , orderPriority);
                    Console.WriteLine();

                    parameters.Add("OrderAmount", orderAmount);
               }


3.   Add the following code to the end of the OnWorkflowIdled method. It is explained directly following.

                  // If selection = 2, change RuleSet rule condition
                 if (selection == "2" & !wasChanged)
                 {
                     wasChanged = true;
                     Console.WriteLine("Dynamically changing hard-coded order amount
threshold in RuleSet to 25000");

                     // Retrieving a workflow isntance and cloning it
                     WorkflowInstance workflowInstance = e.WorkflowInstance;

                      // Dynamic update of order rule
                      WorkflowChanges workflowchanges =
                       new
WorkflowChanges(workflowInstance.GetWorkflowDefinition());

                     CompositeActivity workflowActivityToChange =
                         workflowchanges.TransientWorkflow;

                     RuleDefinitions ruleDefinitions =
(RuleDefinitions)workflowActivityToChange.GetValue(RuleDefinitions.RuleDefinitionsProperty);

                     RuleSet ruleSet =
ruleDefinitions.RuleSets["CalculateOrderPriority"];

                     foreach (Rule rule in ruleSet.Rules)
                     {
                         if (rule.Name == "SetPriority")
                         {
                            RuleExpressionCondition condition =
                                rule.Condition as RuleExpressionCondition;

                            CodeBinaryOperatorExpression expression
                                = condition.Expression as
CodeBinaryOperatorExpression;

                           //Resetting the hard-coded order amount threshold
                         expression.Right = new CodePrimitiveExpression(25000);
                      }
                  }
                  workflowInstance.ApplyWorkflowChanges(workflowchanges);
    }

     The code is identical to the code that changed the rule condition with three exceptions. First, the ruleDefinitions.RuleSets property is accessed instead of ruleDefinitions.Conditions property, because we are accessing RuleSet rules and not rule conditions. Second, the SetPriority rule is selected by iterating the rule in the ruleDefinitions.RuleSets collection. Finally, after the SetPriority rule is located, the CodeDom is used to change the condition from OrderAmount > 100000 to OrderAmount > 25000.

4.   Run the workflow, enter 2 when prompted, and you should receive the results shown in Figure 15.7. The key again is that regular shipping is received on the first iteration and special shipping on the second. In this case, the BranchCondition rule condition remains orderPriority == 1. It is the SetPriority RuleSet rule that changes the value of the orderPriority from 2 to 1, which causes the “standard” BranchCondition rule evaluation to change from false to true.

FIGURE 15.7 Results of running workflow with a RuleSet rule dynamically changed in second iteration.

Results of running workflow with a RuleSet rule dynamically changed in second iteration.

Image

Other RuleSet and rule attributes, such as whether the rule is active and whether the RuleSet supports forward chaining, can also be updated via the Rule and RuleSet types.

Change RuleSet Rule via .rules File

So far you have changed the RuleSet and Conditions properties via the CodeDom and then passed them to the WorkflowChanges object. A viable alternative approach is to change the .rules file that contains the serialized RuleSet and Conditions. From there, you can update the RuleSet or Conditions properties with the updated .rules file that contains the new values. This method can be used to support directly updating the .rules file to implement ad hoc changes or to fix bugs, for instance. As you saw in Hour 12, the RuleSet Dialog Editor can be rehosted. Using the RuleSet Dialog Editor or your own custom one, the .rules file could be edited by business users throughout the workflow life cycle. This may be appropriate for some long-running workflows that could then update the rules at each persistence point. Let’s begin.

Follow the next steps to change a rule in a .rules file.

1.   Disable the SetOrderPriority activity.

2.   Add the following code to the Program.cs Main method below the ending bracket of the if (selection == "2") if statement. This passes the proper parameters to run scenario 3 (change RuleSet rule via .rules file).

               // Dynamically chnage RuleSet rule condition via .rules file
               if (selection == "3")
               {
                   Console.WriteLine("The OrderPriority is set to 1 for Orders >
100k which earns them special shipping.");
                   Console.Write("(The intitial OrderAmount value = $50,000).",
orderPriority);
                   Console.WriteLine();

                   parameters.Add("OrderAmount", orderAmount);
                }

3.   Add the following code to the end of the OnWorkflowIdled method. It is explained directly following:

               // Update RuleSet rule via .rules file
               if (selection == "3" & !wasChanged)
               {
                   wasChanged = true;

                   Console.WriteLine("Dynamically changing hard-coded order amount
threshold in RuleSet to 25000");

                   // Retrieving a workflow isntance and cloning it
                   WorkflowInstance workflowInstance = e.WorkflowInstance;

                   // Next two lines serialize external rules into a type
                   WorkflowMarkupSerializer serializer =
                       new WorkflowMarkupSerializer();
                   XmlTextReader reader =
                       new
XmlTextReader(@"SamsWf24hrsHoursHour15DynamicUpdateDynamicUpdateRulesD
ynamicUpdateRulesManuallyUpdateRulesFile.rules");

                      WorkflowChanges workflowchanges =
                          new
WorkflowChanges(workflowInstance.GetWorkflowDefinition());

                   CompositeActivity workflowActivityToChange =
                       workflowchanges.TransientWorkflow;

                   // Get ruleDefinitions from exteranl rule


         RuleDefinitions ruleDefinitions =
serializer.Deserialize(reader) as RuleDefinitions;

                       // Replace the current rules value DependencyProperty with
the value
                      // from the external rules.

workflowActivityToChange.SetValue(RuleDefinitions.RuleDefinitionsProperty,
ruleDefinitions);

                      workflowInstance.ApplyWorkflowChanges(workflowchanges);
                      }

There are two changes. A new WorkflowMarkupSerializer type is instantiated. The WorkflowMarkupSerializer type can serialize and deserialize XAML and .rules files (see the next note). In this case, it is used to deserialize the .rules file (convert it to a .NET type). The deserialized .rules file is then passed to an XmlTextReader type on the next line. The line of code shown next uses the WorkflowMarkupSerializer to deserialize the reader that contains the .rules file.

                       // Get ruleDefinitions from exteranl rule
                       RuleDefinitions ruleDefinitions = serializer.Deserialize(reader)
as RuleDefinitions;

Image

WF’s two main formats are .NET types or XML, with the XML split between XAML and .rules formats. There are times it is needed or handy to convert between these formats, which is what WF does internally when a XAML workflow is complied at design time or received at runtime. The WorkflowMarkupSerializer type that permits this format conversion is not covered further in this book. See the applications in your sample directory WFTechnologiesMarkup if you are interested in learning more about WF serialization.

The rules in the RuleDefinitions property are now those contained in the .rules file (which presumably contains changes). When updating rules via the CodeDom, the initial RuleDefinitions was obtained from the RuleDefinitionsProperty dependency property.

               RuleDefinitions ruleDefinitions =
                   (RuleDefinitions)workflowActivityToChange.GetValue
                   (RuleDefinitions.RuleDefinitionsProperty);

Finally, you update the DependencyProperty that holds the RuleDefinitions property as shown:

workflowActivityToChange.SetValue(RuleDefinitions.RuleDefinitionsProperty,
ruleDefinitions);

1.   Browse to the ManuallyUpdateRulesFile.rules file in the C:SamsBookHoursHour15DynamicUpdateDynamicUpdateDynamicUpdateRulesDynamicUpdateRules directory and open the file with Notepad.

2.   Search for 100000 and change the 100000 to 25000. Then save the file.

3.   Run the workflow, enter 3 when prompted, and you should receive the results shown in Figure 15.8. The key again is that regular shipping is received on the first iteration and special shipping on the second. In this case, lowering the order threshold from 100,000 to 25,000 is done by changing the .rules file.

FIGURE 15.8 Results of running workflow with a RuleSet rule dynamically updated from a .rules file in second iteration.

Results of running workflow with a RuleSet rule dynamically updated from a .rules file in second iteration.

Dynamic Update: Exploring Workflow Changes Sample

One of the WF developers at Microsoft created a sample application named Workflow Changes that adds visibility to Dynamic Update and integrates it with tracking in a similar manner to the WorkflowMonitor SDK sample demonstrated in Hour 5, “Creating an Escalation Workflow.” It demonstrates the kinds of applications that can be constructed by developers or that may be added by Microsoft and/or third parties using WF as a platform. The application itself does not appear ready for production use. It is shown again because of how well it expresses key WF potential application. There is no code in this section. If you want to learn more, you can follow a link to the application, which includes source code, at the end of this section.

The ability to update workflows midprocess is very powerful. However, our Dynamic Update implementation to date has lost a good deal of two of WF’s key features: design-time transparency and graphical construction. Runtime transparency has been maintained via tracking; however, even then the tracking display used leaves room for improvement.

The Workflow Changes application allows you to graphically modify running workflows using the same workflow designer used to create workflows in Visual Studio. Your changes are thereby reflected in the designer as you make them. The Workflow Changes application extends the design-time experience and transparency to runtime change. Let’s take a look at the Workflow Change application.

Figure 15.9 shows the main form. From this form you can select to view currently running or previously executed workflows. You can double-click one of the currently running workflows to bring it up in detail view. The difference (as shown in Figure 15.10) is that a menu appears across the top, where you can suspend, resume, terminate, or change the workflow. An activity toolbox and property windows also show up in a right pane, though they are not yet active.

FIGURE 15.9 Workflow Change application main form.

Workflow Change application main form.

FIGURE 15.10 Workflow Change application detail form.

Workflow Change application detail form.

After you select Change Workflow, the activity toolbox and property window are activated. What does this mean? You can add activities to this workflow instance from the toolbox as you normally do in Visual Studio. As shown in Figure 15.11, a Parallel activity was added, and a Suspend activity was placed in each branch.

FIGURE 15.11 The Workflow Change application is used to add activities to a running workflow instance.

The Workflow Change application is used to add activities to a running workflow instance.

Now click the Accept Changes button, and all the Dynamic Update logic is handled behind the scenes. From the user standpoint, locate a workflow, add new activities, and apply the changes. You can even run the workflow from the UI by clicking the Resume button, which, as shown in the left pane of Figure 15.11, executes the remaining activities. Finally, you can view the results in tracking (not shown) so that the changes made to each workflow can be identified.

Image

Some of you may have noticed that the activity toolbox contained only a subset of the standard WF activities. There was also a custom activity named Activity1. When rehosting the designer, you choose which activities to display and in many cases it is likely that many custom activities exist, such as Customer and Order, that allow business analysts to create simple workflows. Designer rehosting is not covered in this book. The workflow designer, though, is a Windows Control that can be hosted in a .NET 2.0 and later application. See the DesignerHosting SDK sample or the “Windows Workflow Foundation: Everything About Re-Hosting the Workflow Designer” article for more information on designer rehosting. The article comes with a comprehensive sample application that permits compilation, rules rehosting, and contains all WF OOB activities. In Hour 17, “Learning Advanced Hosting,” you will learn about the WF workflow loading methodology that can be used to process a workflow created in Visio or another modeling tool, which offers an alternative to designer rehosting.

The Workflow Change application shows how a combination of WF features—Dynamic Update, designer rehosting, tracking, abstracted validation, general workflow designer transparency—combine to add efficiencies to the software development, run, modify, and deployment processes, as shown in Figure 15.12.

FIGURE 15.12 Software development process enabled by Workflow Change application.

Software development process enabled by Workflow Change application.

The concept of the Workflow Changes application is useful to permit business analysts and other nondevelopers to create simple workflows. It is also useful to developers as part of the general development process. The business analysts would have limited activities that allow for simpler, confined workflow creation. The developers would, on the other hand, have a richer set of activities and capabilities.

Here is the URL to the Workflow Change application if you want to learn more: http://wf.netfx3.com/files/folders/sample_applications/entry4074.aspx.

Summary

Dynamic Update is useful to change one, selected, all future, and other permutations of workflow instances at runtime or even thereafter. When adding and removing activities, the changes are reflected in tracking, which serves as an interesting versioning mechanism. When rules are changed, they are not reflected in tracking, which is unfortunate. It may, however, fall in the realm of a server product and not a workflow/rules platform to provide this functionality. Dynamic Update is fairly hard to use, and XAML-only workflows overlap in some areas. It will be interesting to see where Dynamic Update goes in future versions.

Workshop

Quiz

1.

What is the purpose of Dynamic Update?

2.

What changes can be made with Dynamic Update?

3.

What are the two types used in Dynamic Update?

4.

What is the function of the WorkflowChanges type?

5.

What is the function of the WorkflowInstance type in relation to Dynamic Update?

6.

What are the three steps to implementing Dynamic Update?

7.

What are the main differences between applying Dynamic Update from the inside and the outside?

8.

What is the difference between performing Dynamic Update from the outside planned and unplanned?

9.

What steps must be performed to update a declarative rule condition that are not necessary when using Dynamic Update and not updating rules?

Answers

1.

To change selected workflows at runtime.

2.

Activities can be added and deleted and RuleSet rules and declarative rule conditions can be changed.

3.

WorkflowChanges and WorkflowInstance.

4.

Through its TransientWorkflow property, the WorkflowChanges type holds a cloned copy of the workflow that can be updated and then used to replace the current workflow instance.

5.

The WorkflowInstance.ApplyWorkflowChanges method replaces the currently running workflow with the changed workflow.

6.

Pass a workflow definition to the WorkflowChanges type, make changes to the WorkflowChanges.TransientWorkflow property, and then apply the changes via the WorkflowInstance.ApplyWorkflowChanges method.

7.

The original workflow to be modified is retrieved through the WorkflowInstance.GetWorkflowDefintion method instead of (this) and you have to find a “safe” point to perform the changes, such as when the workflow is idled.

8.

When performing Dynamic Update from the outside planned, you know where on the workflow it may be changed and can therefore suspend it. You can make the changes safely and securely because you know where the workflow is and that it is and will remain stopped. Performing it unplanned requires you to attempt to inject your changes at a persistence point if possible or through workflow queues. Making the changes unplanned makes it difficult to ensure the workflow is in the state you want it to be in at the time of change.

9.

Instantiate a RuleDefinitions type with the RuleDefinitionsProperty dependency property. Instantiate the RuleDefinitions.Conditions typed variable. Make the changes to the RuleDefinitions.Conditions typed variable via the CodeDom.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.191.239.235