Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Dotnet Simple Rule Engine

0.00/5 (No votes)
16 Jun 2015 1  
Dotnet Simple Rule Engine

Introduction

A Business Rule Engine is a software program which executes one or more business rules on behalf of other programs. This software provides convention, grammar or UI Interface which can be used by Business Person. They can define the rules without knowing the programming. Rules can be changed dynamically without changing the application code. I found Simple Rule Engine source code on http://www.csharpopensource.com/ site, downloaded the code, compiled it on Microsoft Dotnet version 4.0 to make it compatible with current
industry standard.

Background

A brief tutorial is available at http://simpleruleengine.tripod.com/.

I am going to provide the tutorials which help in understanding and sample program to use it.

Installation

We can install the compiled package using nuget Manager. It is now available as nuget package https://www.nuget.org/packages/SimpleRuleEngine.

To install it through nuget, use PM > Install-Package SimpleRuleEngine.

Business Requirement

  • Tax Calculator application which runs on the below business logic
  • If Gross Salary is less than Rs. 500,000/- for a year, there is no tax and Net Salary is same as Gross Salary.
  • If Gross Salary is between 500,000/- and 800,000/- for a year, tax will be 20 percent of Gross Salary. Net Salary will be equal to Gross Salary minus Tax.
  • If Gross Salary is equal or greater than Rs. 800,000/- for a year, tax will be 30 percent of Gross Salary and Net Salary will be equal to Gross Salary minus Tax.

Solution

The above problem can be achieved in different and multiple ways. But I am going to use the simple rule engine to achieve this.

  1. Open Visual Studio and create a sample Console application with name Tax Calculator.
  2. Add nuget package manager to add PM> Install-Package SimpleRuleEngine.
  3. Add one class RuleExecutor to execute the above rule.
    internal sealed class RuleExecutor
        {
            public void ExecuteTaxRules()
            {
                XmlDocument rules = new XmlDocument();
    
                string directory = AppDomain.CurrentDomain.BaseDirectory + @"\TaxCalculator.xml";
    
                rules.Load(directory);  
                //model
                XmlDocument model = new XmlDocument();
                model.LoadXml(@"<Employee><GrossSalary>900000</GrossSalary>
                <HRA>50000</HRA><Tax></Tax><NetSalary>
                </NetSalary></Employee>");
             
                ROM rom = Compiler.Compile(rules);
                rom.AddModel("Employee", model);
                rom.Evaluate();
                var tax = model["Employee"]["Tax"].InnerText;
                var NetSalary = model["Employee"]["NetSalary"].InnerText;
                var message = string.Format("Tax: {0} and Net take home salary :{1}", tax, NetSalary);
                Console.Write(message);
                Console.Read();
    }
    }
  4. We can define the rule in XML format and Simple Rule engine will execute, apply the rule and will give the output.
    <?xml version="1.0" encoding="utf-8" ?>
    <RuleEngine>
    
      <Rules>
        <Rule id="RuleNoTax" desc="Rule for no tax" chainable="true"  priority="100">
          <Condition><![CDATA[ GrossSalary < 500000 ]]></Condition>
          <Actions>
            <Evaluate factId="Tax" ><![CDATA[0]]></Evaluate>
            <Evaluate factId="NetSalary"><![CDATA[ GrossSalary ]]></Evaluate>
            <Execute factId="RuleMediumTax"/>
          </Actions>
        </Rule>
     
     
        <Rule id="RuleMediumTax" desc="Rule for Medium tax" chainable="true"   priority="19">
          <Condition><![CDATA[ (GrossSalary>=500000) AND (GrossSalary<800000)]]></Condition>
          <Actions>
            <Evaluate factId="Tax" priority="11"><![CDATA[ (GrossSalary *2/10)  ]]></Evaluate>
            <Evaluate factId="NetSalary" priority="1"><![CDATA[ (GrossSalary-Tax) ]]></Evaluate>
            <Execute factId="RuleHighTax"/>
          </Actions>
    
        </Rule>
        <Rule id="RuleHighTax" desc="Rule for High tax"  chainable="true"  priority="2">
          <Condition><![CDATA[ GrossSalary>=800000]]></Condition>
          <Actions>
            <Evaluate factId="Tax" priority="2" ><![CDATA[ GrossSalary*3/10 ]]></Evaluate>
            <Evaluate factId="NetSalary" priority="1"><![CDATA[ GrossSalary-Tax ]]></Evaluate>
          </Actions>
        </Rule>
        
      </Rules>
    
      <Facts>
        <Fact id="GrossSalary" desc="Gross Salary" type="double" modelId="Employee">
          <xpath><![CDATA[ number(Employee/GrossSalary) ]]></xpath>
        </Fact>
        <Fact id="HRA" desc="House Rent Allowance" type="double" modelId="Employee">
          <xpath><![CDATA[ Employee/HRA ]]></xpath>
        </Fact>
        <Fact id="Tax" desc="Tax" type="double" modelId="Employee">
          <xpath><![CDATA[ Employee/Tax ]]></xpath>
        </Fact>
        <Fact id="NetSalary" desc="Net Salary" type="double" modelId="Employee">
          <xpath><![CDATA[ Employee/NetSalary ]]></xpath>
        </Fact>
     
     
      </Facts>
    
    </RuleEngine>
  5. Now update the Program class as shown below:
     class Program
        {
            static void Main(string[] args)
            {
                var re = new RuleExecutor();
                re.ExecuteTaxRules();
            }
        }
  6. 6. Compile and run the program with different values of Gross salary element in XML model.

So here, today we learnt how we can put complex business logic separate from main program and execute it separately.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here