Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / web / HTML

Basic Help on NxBRE (Rule Engine)

CPOL1 min read 72.7K   2.3K  
Here is a help on NxBRE (Rule Engine) for basic business rules

Introduction

In this article, we are going to see how we can apply dynamic business rules on an application without recompiling the code.

Background

My company required to build an ETL and my responsibility was to take care of the "T" Part.

You can found a brief about the DLL NxBRE here: http://sourceforge.net/projects/nxbre/. As I said I am not an expert of Rule engines, but this project might help you. 

It's nice to implement BRE in your application and your intelligence to code and writing business rules will speed up your application otherwise it may hamper performance.

Using the code 

You need VS 2010, this project will show you a small demo of Employee Tax and DA calculation depending on their Basic. Here is the XBRE file which contains the Rule:

XML
<?xml version="1.0" encoding="UTF-8"?>
<xBusinessRules xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
           xsi:noNamespaceSchemaLocation="xBusinessRules.xsd">
  <Decimal id ="Tax" value ="10"/>
  <Decimal id ="DAp" value ="10"/>
 
  <Decimal id="5000" value="5000"/>
  <Decimal id="10000" value="10000"/>
  <Decimal id="15000" value="15000"/>
  <Decimal id="20000" value="20000"/>
  <Decimal id="30000" value="30000"/>
  <Decimal id="100000" value="100000"/>
  
  <!-- Calculation Of Tax -->
  
  <ObjectLookup id ="EmpObj" objectId ="EmpTexCal" member ="BasicSalary"/>
  <Logic>
    <If>
      <And>
        <Between leftId ="5000" rightId ="10000" valueId ="EmpObj">
        </Between>
      </And>
      <Do>
        <Modify id ="Tax" type="Decimal" value ="11.5"/>
      </Do>
    </If>
    <ElseIf>
      <And>
        <Between leftId ="10000" rightId ="15000" 
                  valueId ="EmpObj" excludeLeft ="true">
        </Between>
      </And>
      <Do>
        <Modify id ="Tax" type="Decimal" value ="13.5"/>
      </Do>
    </ElseIf>
    <ElseIf>
      <And>
        <Between leftId ="15000" rightId ="20000" 
                    valueId ="EmpObj" excludeLeft ="true">
        </Between>
      </And>
      <Do>
        <Modify id ="Tax" type="Decimal" value ="14.5"/>
      </Do>
    </ElseIf>
    <ElseIf>
      <And>
        <Between leftId ="20000" rightId ="30000" 
                      valueId ="EmpObj" excludeLeft ="true">
        </Between>
      </And>
      <Do>
        <Modify id ="Tax" type="Decimal" value ="15.5"/>
      </Do>
    </ElseIf>
    <ElseIf>
      <And>
        <Between leftId ="30000" rightId ="100000" 
                    valueId ="EmpObj" excludeLeft ="true">
        </Between>
      </And>
      <Do>
        <Modify id ="Tax" type="Decimal" value ="17"/>
      </Do>
    </ElseIf>
  </Logic>
 
  <!-- <ObjectLookup id ="EmpObjOut" 
               objectId ="EmpTexCal" member ="TaxPercentage">
    <Argument valueId="Tax"/>
 </ObjectLookup> -->
  <!-- Calculation Of DA -->
  <Logic>
    <If>
      <And>
        <Between leftId ="5000" rightId ="10000" valueId ="EmpObj">
        </Between>
      </And>
      <Do>
        <Modify id ="DAp" type="Decimal" value ="25"/>
      </Do>
    </If>
    <ElseIf>
      <And>
        <Between leftId ="10000" rightId ="15000" valueId ="EmpObj" excludeLeft ="true">
        </Between>
      </And>
      <Do>
        <Modify id ="DAp" type="Decimal" value ="30"/>
      </Do>
    </ElseIf>
    <ElseIf>
      <And>
        <Between leftId ="15000" rightId ="20000" valueId ="EmpObj" excludeLeft ="true">
        </Between>
      </And>
      <Do>
        <Modify id ="DAp" type="Decimal" value ="40"/>
      </Do>
    </ElseIf>
    <ElseIf>
      <And>
        <Between leftId ="20000" rightId ="30000" valueId ="EmpObj" excludeLeft ="true">
        </Between>
      </And>
      <Do>
        <Modify id ="DAp" type="Decimal" value ="50"/>
      </Do>
    </ElseIf>
    <ElseIf>
      <And>
        <Between leftId ="30000" rightId ="100000" valueId ="EmpObj" excludeLeft ="true">
        </Between>
      </And>
      <Do>
        <Modify id ="DAp" type="Decimal" value ="60"/>
      </Do>
    </ElseIf>
  </Logic>
  <!-- Example Of Evaluation -->
  <ObjectLookup id="ExpDAp"	type="NxBRE.Imp.Util.Evaluator,NxBRE.Imp" member="CreateExpression">
    <Argument value="(" />
    <Argument valueId="EmpObj" />
    <Argument value="/" />
    <Argument value="100" />
    <Argument value=")" />
    <Argument value="*" />
    <Argument valueId="DAp" />
  </ObjectLookup>
  <ObjectLookup id="EvalDAp"	type="NxBRE.Util.Compilation" member="Evaluate">
    <Argument valueId="ExpDAp" />
  </ObjectLookup>
  <ObjectLookup id="CastDAp"	type="NxBRE.Imp.Util.Casting,NxBRE.Imp" member="CastData">
    <Argument valueId="EvalDAp" />
    <Argument value="System.Decimal" />
  </ObjectLookup>
  <ObjectLookup id ="EmpObjOut" objectId ="EmpTexCal" member ="DA">
    <Argument valueId="CastDAp"/>
  </ObjectLookup>
</xBusinessRules> 

Here is how to read the XBRE file, I will explain the XBRE file later:

C#
public ReadRule(string RuleFilePath)
{
    _FilePath = RuleFilePath;
    StringBuilder sb=new StringBuilder(255);

    if (GetShortPathName(_FilePath, sb, sb.Capacity) != 0)
        _factory = new BREFactoryConsole(_engineTraceLevel, _ruleBaseTraceLevel).NewBRE(new XBusinessRulesFileDriver(sb.ToString()));
}

You can change trace level to get trace result. I have two separate concerns: one is reading rule from a file and setting values for depending calculations.

Set value of depending variables. Set value of a particular object. 

C#
public void SetObjectRefrance(ReadRule objRule, string ObjectId, object Obj)
{
    if (objRule.IsValidXML)
    {
        if (objRule.IsProcessed)
            objRule.Reset();
        objRule.Factory.RuleContext.SetObject(ObjectId, Obj);
    }
}

We can set any delegate of ExecuteRuleDelegate type through which we can call back our base code while performing rules.

C#
public void SetDelegateRefrance(ReadRule objRule, string ObjectId, ExecuteRuleDelegate Delegate)
{
    if (objRule.IsValidXML)
    {
        if (objRule.IsProcessed)
            objRule.Reset();
        objRule.Factory.RuleContext.SetFactory(ObjectId, new BRERuleFactory(Delegate));
    }
}

In this rule engine we can split our rule concern and perform partial rule or we can perform the rule but fetch only partial result values.

* We have to set depending values or the Delegate.

C#
public object GetRuleResult(ReadRule objRule, string ObjectId)
{
    try
    {
        if (!objRule.IsProcessed)
            objRule.ProcessRules();
        return objRule.Factory.RuleContext.GetResult(ObjectId).Result;
    }
    catch (Exception)
    {
    }

    return FlagResualt.NoProcessed;
}

Now I have created a combine function which will take care of all of the above functions:

C#
public void EvaluateRule(ReadRule objRule, RuleRefrance[] RulesReferances, 
              RuleDelegate[] RulesDelegates, RuleResualt[] RuleReply)
{
    if (RulesReferances != null)
        AddObjects(objRule, 0, RulesReferances);
    if (RulesDelegates != null)
        AddDelegates(objRule, 0, RulesDelegates);
    // Process Rules
    if (!objRule.IsProcessed)
        objRule.ProcessRules();

    //if (RuleReply != null)
    GetObjectResult(objRule, 0, RuleReply);

}

GetObjectResult just sets values at our ORM or any other class using Reflection.

Now how to call all of this and get the rule output, it's very simple:

License

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