Implement simple rules engine using DLR and IronPython.net

The Domain

Here we have an application where we take some details from the customer who wants to apply for a loan. When the customer fills in a “LoanApplication“, we then evaluate it against some eligibility rules and decide whether to further process the application or not.

Before we ventured into Dlr and IronPython.Net, we had:

A Property in our Base Class to hold the Eligibility Rules:

Protected Property EligibilityRules As Dictionary(Of Func(Of LoanApplication, Boolean), String)

In the inherited classes we would override the method and fill in the business rules.

Public Overrides Sub BuildEligibilityRules()
        EligibilityRules.Add(Function(loanApp) CustomerMustBeOver30(), "Customer must be over 30.")
End Sub

Private Function CustomerMustBeOver30() As Boolean

     Return LoanApplication.Customer.Age > 30 
End Function

We then had a runner that ran the rules and if any of them failed, we would reject the application.

These rules were ever-changing and we needed a better way to change the rules without deploying the system What we needed was a way to store these rules as string in the database. Then in c# runtime load the rules, parse them and finally execute them. (you get the idea!)

The solution we came up with was to use IronPython and dlr to execute it. So we would store the rule in the database as

"loanApplication.LoanAmount > 0",
"loanApplication.Customer.Age < 30",
"loanApplication.Customer.Name",
"loanApplication.LoanAmount < loanApplication.Customer.YearlyIncome"

Because these are simple string, we can now store them in the database and read it into a list of something like:

var EligibilityRules = new List<string> { 
                  "loanApplication.LoanAmount > 0", 
                  "loanApplication.Customer.Age < 30", 
                   "loanApplication.Customer.Name",
                  "loanApplication.LoanAmount < loanApplication.Customer.YearlyIncome" };

In order to execute them, we did the following:

Download and install the IronPython nuget package:
PM> Install-Package IronPython -Version 2.7.4

Then in the code something like this:

using IronPython.Hosting;
using Microsoft.Scripting.Hosting;
using NUnit.Framework;
using Subject;

namespace Rules
{
    [TestFixture]
    public class Tests
    {
        private Customer _customer;
        private LoanApplication _loanApplication;
        private ScriptEngine _engine;
        private ScriptRuntime _runtime;
        private ScriptScope _scope;

        public bool IsEligible()
        {
            _customer = new Customer {Age = 25, Name = "XYZ", YearlyIncome = 15000m}; // create the customer
            _loanApplication = new LoanApplication(_customer, 1000m); // create a loan application
            _engine = Python.CreateEngine(); // create python engine
            _runtime = _engine.Runtime; // create the runtime for the engine
            _scope = _runtime.CreateScope(); // create the scope in which you are going to execute the script
            var loanShark = new LoanShark(); // dummy loan company
            foreach (var eligibilityRule in loanShark.EligibilityRules) // loop through the rules for this loan provider
            {
                var script = _engine.CreateScriptSourceFromString(eligibilityRule); // create the python script out of the rule at hand
                _scope.SetVariable("loanApplication", _loanApplication); // in the rule "loanApplication.LoanAmount > 0", replace the "loanApplication" with the real loanApplication Object
                var isEligible = script.Execute<bool>(_scope);// execute and get the result as a boolean
                if (!isEligible) return false;

            }
            return true;
        }

…………………….

This proved to be a very effective technique, as now we could give users “Enterprise library” like interface to construct these rules “safely” on the Fly and store them in the database. On the other side we would read these rules and simply execute them.

You can find all the code for the above example at GitHub.

If you want to learn more about IronPython have a look at : IronPython web site

some more DLR information at: MSDN DLR Site

Leave a Reply

%d bloggers like this: