Changing a Declarative Rule Condition at runtime

One powerful feature of a workflow is that a workflow can be changed at runtime. Like other powerful features this is something that should be done with care but it can be a real life saver at times.

One of the things that you can change are Declarative Rule Conditions. However as these rules are really CodeDom objects it can be a bit tricky to find the right property to change. However once you know a little tick life is much easier.

The trick is in the .rules file created when you add a Declarative Rule Condition to the workflow and is best demonstrated using a small example. Take the following workflow:

image

 

The IfElseActivity has a Declarative Rule Condition which looks like this:

image

So I consider every amount larger that 100 large. Hmm not much, lets change that to 1000 instead of 100 [:)]

The first step is we need to change the workflow instance so we need a WorkflowChanges object passing in the workflow root as the activity. No big deal but what now. Well lets open the Workflow1.Rules file and take a look at what is inside.

<RuleDefinitions xmlns="http://schemas.microsoft.com/winfx/2006/xaml/workflow">
    <RuleDefinitions.Conditions>
        <RuleExpressionCondition Name="LargeAmountRule">
            <RuleExpressionCondition.Expression>
                <ns0:CodeBinaryOperatorExpression Operator="GreaterThan" xmlns:ns0="clr-namespace:System.CodeDom;Assembly=System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
                    <ns0:CodeBinaryOperatorExpression.Left>
                        <ns0:CodePropertyReferenceExpression PropertyName="Amount">
                            <ns0:CodePropertyReferenceExpression.TargetObject>
                                <ns0:CodeThisReferenceExpression />
                            </ns0:CodePropertyReferenceExpression.TargetObject>
                        </ns0:CodePropertyReferenceExpression>
                    </ns0:CodeBinaryOperatorExpression.Left>
                    <ns0:CodeBinaryOperatorExpression.Right>
                        <ns0:CodePrimitiveExpression>
                            <ns0:CodePrimitiveExpression.Value>
                                <ns1:Int32 xmlns:ns1="clr-namespace:System;Assembly=mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">100</ns1:Int32>
                            </ns0:CodePrimitiveExpression.Value>
                        </ns0:CodePrimitiveExpression>
                    </ns0:CodeBinaryOperatorExpression.Right>
                </ns0:CodeBinaryOperatorExpression>
            </RuleExpressionCondition.Expression>
        </RuleExpressionCondition>
    </RuleDefinitions.Conditions>
</RuleDefinitions>

 


It turns out that the XML is a very literal representation of the objects that make up our rule and what we need to change. So we need to start with a RuleDefinitions.


 

RuleDefinitions rules =
    (RuleDefinitions)changes.TransientWorkflow.GetValue(RuleDefinitions.RuleDefinitionsProperty);

So getting our hand on it is easy, just use the GetValue function passing in the RuleDefinitionsProperty dependency property.


Once we have this things are even easier as it is just following the XML [:)]. It shows the RuleDefinitions object has a Conditions property and our rule is in there with a name LargeAmountRule and is of type RuleExpressionCondition. This rule in turn contains a left and right part with the right part pointing at the value of 100 we want to change. Again this value is of a type CodePrimitiveExpression, another easy cast. The code below is the complete code required to change the value from 100 to1000.

WorkflowChanges changes = new WorkflowChanges(this);

RuleDefinitions rules =
    (RuleDefinitions)changes.TransientWorkflow.GetValue(RuleDefinitions.RuleDefinitionsProperty);

RuleExpressionCondition rule = (RuleExpressionCondition)rules.Conditions
    .First(rc => rc.Name == "LargeAmountRule");
CodeBinaryOperatorExpression expression = (CodeBinaryOperatorExpression)rule.Expression;
CodePrimitiveExpression primitive = (CodePrimitiveExpression)expression.Right;
primitive.Value = 1000;

ApplyWorkflowChanges(changes);

 


Easy once you know where to look [:)]


Enjoy!


 


[f1]
[f2]


7 thoughts on “Changing a Declarative Rule Condition at runtime

  1. How would you implement this on say a live site? Would you simply build a little console app for the project simply for uploading changes to the workflow? Or would you have to plumb this code into the main system to update every single workflow item created?

    And does this update a single instance or the workflow as a whole?

  2. These changes are only for a single workflow instance. So you will need to examine every existing workflow, determine if changes are needed to the workflow type and if so make the changes.

    I typically add this to the actual host program as this is something you cannot do until you have started the WF runtime. And that means the workflows can start running so you need to have the proper runtime configuration.

    Sorry about the code being truncated. Even though you cannot see the code you can still select all the lines and copy it to notepad. Not perfect but at least a workaround so you can see all the code. I will take more care in the future.

  3. Hello Maurice and any WF developer reading.
    This is a good site for reference and a good repository of samples.
    I’m currently doing a research on rule engines in order to replace some code implemented in stored procedures. My team needs to cut down the proliferations of repeated t-sql code and make use of OO to declare the rules.

    One of our main requirements is that business analysts that are most of the time not very technical should be able to draw or diagram the rule.

    Being able to version or set the rule’s effective date is a plus as well.

    afaik, WF designer is embedded in the VS IDE, so the analysts would have to have the IDE installed.

    There are some java based rule engines such as Jess and FairIssaac’s ModelBuilder.

    Is there any study or white paper alreday published on this topic that we could be referred to?

    TIA!

    Lizet

  4. @Lizet,

    The workflow designer is rehostable in your own applications. Right now it might not be quite as easy as you would like but it is completely doable. Using the rehosted designer you can save workflows and rules as XOML, ie XML, files. That might not be perfect for diffing but any tool like WinDiff will be able to show you the differences between the two versions.

    When you start a workflow using XOML you pas the rules as a separate file. That way it is easy to pass in different rules for the same workflow dependent on a specific criteria like the start date. That might not solve your problem for long running though.

    I am not aware of any white papers comparing WF against Java based rules engines. They might very well be out there but I have never seen them.

  5. Hello Maurice,
    Thank you for commenting back. We will get a look at how to re-host the designer within an application so the business analysts can outline the rules without the need of a developer. It’s a good start.

    I already bookmarked your site and I’m sure I’ll come back to it quite often for reference.

    Thanks!

Leave a Reply

Your email address will not be published. Required fields are marked *


*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>