Click here to Skip to main content
15,867,308 members
Articles / Desktop Programming / Windows Forms

Trigger Based Rule Engine

Rate me:
Please Sign up or sign in to vote.
4.60/5 (4 votes)
17 Jun 2009CPOL3 min read 46.1K   838   38   6
Simple Rule Engine with Triggers to apply the rule

Introduction

Business rules form an integral part of many applications. Rules are usually conditional and the evaluation of the rules is triggered by the user input.

Simple rule engine is an attempt to create a rule engine which externalizes both the rule and the trigger.

Rule Engine

It can be explained better with an example:

Consider a simple application which accepts details of a person and determines if the person depending on his age can go out alone:

  • Name
  • Age
  • CanGoOutAlone

Rule:

  • If the age of the person is less than 15, he cannot go out alone else he can, however person "BAKTHA" is an exception and can go out alone irrespective of how old he is.

Different approaches to implement triggers and the rule itself which can come to our mind are:

  1. Coding in the view model
  2. Event handling
  3. Work flow Rules Engine

Each has some drawbacks:

  • Coding in the view model: Code written in the view model tends to clutter the code file.
  • Event handling: UI Code is the simplest way to implement this code but changing the code is difficult, also sometimes the necessary events are not available.
  • Workflow rules engine: Needs to be triggered explicitly.

Additionally, except for Workflow Rules Engine, the rules have to be coded and are not externalized (in Workflow Rule Engine though they are externalized, they are not meant to be edited by a simple XML editor and are verbose enough to prevent you from doing so).

First, let's understand what we require for a simple rule engine:

  • If the rule is conditional, like the one mentioned in the example, then the condition has to be evaluated before the rule has to be applied - Condition Part
  • When the variables used in the condition change, the condition has to be evaluated and the rule has to be applied if the condition is satisfied - Trigger Part
  • Action to be performed when the condition is satisfied - Actual rule to be applied

Another way triggers can be implemented is by using Data Binding Framework provided by WPF.

WPF provides a powerful feature, Data Binding which allows binding CLR objects to the UI controls. I would not delve much into Data Binding. This article assumes you have some knowledge about data binding and dependency properties.

Why do we need data binding for this?

Data binding will provide the trigger which triggers the evaluation of the condition or execution of the action if there's no condition.

Design

Trigger_based_Rule_Engine/RulesEngine.PNG

Background

  • Data Binding
  • Dependency Properties
  • MVVM - Model View ViewModel

Rule Engine - Code

An XML rule entry for the sample application:

The rule is then read by the RulesLoader and converted to condition object, which is evaluated by the Trigger.

XML
<RULES>
  <TRIGGERS>    
    <TRIGGER TYPE="SETTER" ELSE_ACTION="SETTER" PARAMETER="false" 
        PROPERTY_NAME="CanGoOutAlone" VALUE="true" 
	BINDPROPERTY_NAME="" PROPERTY_GROUP="">
      <CONDITIONS>
        <CONDITION TYPE="OR">
          <CONDITION TYPE="AND">
            <CONDITION PROPERTY_GROUP="OBJECT" PARAMETER="" PROPERTY_TYPE="int" 
              PROPERTY_NAME="Age" VALUE="15" CONDITION_TYPE="IsGreaterThanOrEqualTo"/>
            <CONDITION PROPERTY_GROUP="OBJECT" PARAMETER=""  
                PROPERTY_TYPE="string" PROPERTY_NAME="Name" VALUE="XYZ" 
               CONDITION_TYPE="IsNotEqualTo"/>
          </CONDITION>
          <CONDITION PROPERTY_GROUP="OBJECT" PARAMETER="" PROPERTY_TYPE="string"
              PROPERTY_NAME="Name" VALUE="BAKTHA" CONDITION_TYPE="IsEqualTo"/>
        </CONDITION>
      </CONDITIONS>
    </TRIGGER>
  </TRIGGERS>
</RULES> 

Trigger Class

Dependency Property which fires the trigger:

The FireTrigger property is bound to the variable if the trigger is unconditional. When the variable changes, the binding framework invokes the TriggerCallback() method which triggers the execution of the rule.

C#
/// <summary>  
/// Gets or sets the fire trigger.
/// </summary>
/// <value>The fire trigger.</value>
public object FireTrigger
{
get
{
return GetValue(FireTriggerProperty);
}
set
{
SetValue(FireTriggerProperty, value);
}
}
 
public static readonly DependencyProperty FireTriggerProperty = 
    DependencyProperty.Register("FireTrigger", typeof(object), typeof(Trigger),
    new UIPropertyMetadata(null, TriggerCallBack));   
 
/// <summary> 
/// Call back method when the trigger fires.
/// </summary>
private static void TriggerCallBack(DependencyObject obj,
    DependencyPropertyChangedEventArgs e)
{
((Trigger) obj).Execute();
}  

The Execute method evaluates the condition and if the condition is satisfied, then executes the true action or if the else action is specified, then it is executed.

C#
/// <summary> 
/// Execute the trigger code. 
/// </summary>
private void Execute()
{
bool blnIsConditionSatisfied = true;
if (null != triggerCondition)
{ 
blnIsConditionSatisfied = triggerCondition.IsConditionSatisfied();
}
if (blnIsConditionSatisfied)
{
triggerAction.Action();
}
else if (null != triggerElseAction)
{
triggerElseAction.Action();
} 
}   

Condition Class

The condition class evaluates the condition. Several conditions can be joined by using logical condition classes And and Or which perform the logical operations of And'ing and Or'ing the conditions.

Again, Dependency property is used to trigger the evaluation of the condition. As conditions involve variables, the condition has to be reevaluated when there is a change in the variable involved, the RequeryTriggerCondition does exactly that, it reevaluates the entire trigger condition.

C#
/// <summary> 
/// Gets or sets the fire trigger.
/// </summary> 
/// <value>The fire trigger.</value>
private object RequeryTriggerCondition
{
get
{
return GetValue(RequeryTriggerConditionProperty);
}
set
{
SetValue(RequeryTriggerConditionProperty, value);
}
} 
 
private static readonly DependencyProperty RequeryTriggerConditionProperty = 
    DependencyProperty.Register("RequeryTriggerCondition", typeof(object),
    typeof(Condition), new UIPropertyMetadata(null, ConditionRequeryCallBack));
 
/// <summary>
/// Call back method when the trigger fires.
/// </summary>
private static void ConditionRequeryCallBack(DependencyObject obj,
     DependencyPropertyChangedEventArgs e) 
{ 
var objCondition = (obj as Condition);
if (objCondition != null && null != objCondition.Trigger)
{
objCondition.Trigger.RequeryTriggerCondition();
}
}    

Then the action part.

TriggerAction Class

C#
public abstract class TriggerAction 
{
/// <summary
/// Actions this instance.
/// </summary>
public abstract void Action();
}  

TriggerAction class is an abstract class and has to be inherited to specify custom rules. The trigger is run. It calls the Action() method of the class.

Conclusion

It is easy to develop a simple rules engine using the powers of Binding Framework to provide the triggers. It reduces the coding effort and externalizes the rules and the triggers which can be maintained easily.

History

  • 17th June, 2009: Initial post

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
India India
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralHelp me! Pin
Member 15187116-Oct-09 5:09
Member 15187116-Oct-09 5:09 
GeneralGood One Deepak Pin
bakthavatsalan19-Jun-09 20:29
bakthavatsalan19-Jun-09 20:29 
It will help to Make Complex Rule engine in better format
GeneralGood One Pin
Visu.v18-Jun-09 0:11
Visu.v18-Jun-09 0:11 
QuestionDo you think this is a good representation for the rules? Pin
peterchen17-Jun-09 21:21
peterchen17-Jun-09 21:21 
AnswerRe: Do you think this is a good representation for the rules? Pin
zlezj17-Jun-09 22:53
zlezj17-Jun-09 22:53 
GeneralRe: Do you think this is a good representation for the rules? Pin
Deepak-VS18-Jun-09 1:01
Deepak-VS18-Jun-09 1:01 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.