Building a rule engine in c# (part 7: extending the rule engine with a like operator)

In a comment on the rule engine project (ruleengine.codeplex.com) Damien wrote that he would need a like operator in the rule engine to make string compare with wildcards possible. So i added that feature to the rule engine. You now can write “Name like ‘mathi%'” and if the Name property of an object contains the string ‘mathias’ it would return that object. Here is a test that shows the cases that are now possible with the rule engine.

[TestMethod]
public void SimpleExpressionLikeMethod()
{
    Person person1 = new Person()
    {
        Name = "mathias",
        Age = 36,
        Children = 2,
        Married = true,
        Birthdate = new DateTime(1976, 05, 09),
        CancelBenefits = false,
        ReceiveBenefits = false
    };
    Person person2 = new Person()
    {
        Name = "anna",
        Age = 32,
        Children = 2,
        Married = false,
        Birthdate = DateTime.Now,
        CancelBenefits = false,
        ReceiveBenefits = false
    };
    Evaluator evaluator = new Evaluator();
    var result1 = evaluator.Evaluate<Person>(
        " Name like 'math%' ", person1);
    Assert.AreEqual(result1, true);
    var result2 = evaluator.Evaluate<Person>(
        " Name like '?nn?' ", person2);
    Assert.AreEqual(result2, true);
    List<Person> list = new List<Person>() { person1, person2 };
    foreach(var person in list)
    {
        var result = evaluator.Evaluate<Person>(
            " Name like 'mat%' || Name like 'a??a' ", person); 
        if(result)
        {
            Debug.WriteLine(person.Name);
            Assert.AreEqual(result, true);
        }
    }
}

As you see it there are two wildcard that work. The % wildcard can only be used at the end of the text, for example “Name like ‘mat%'”. The ? wildcard can be used in the at any possition, for example “Name like ‘math?ia?'”.


Building a rule engine in c# (part 6: extentions to the rule engine)

When i started implementing the rule engine project (ruleengine.codeplex.com) it was thought as an example project. But i became some comments on the project that show that some people use the project productive and so i was asked to make some extensions to the rule engine. I am glad that someone uses my work an so i implemented the additional features. But the problem is that all that the description of that new features are spread over the comment sections of different posts. So in this post i want to summerice that features.

The first feature i was asked for by martin is that the rule engine has an is in and is not in operator. The FoundIn operator returns true if a person is in a list of given persons. The NotFoundIn operator gives back true if a person is not in a list of given persons. Here is the test i wrote to see if the operator works.

[TestMethod]
public void SimpleRuleLoaderPersonEvaluateFoundInExpression()
{
    Person person1 = new Person() { Name = "Mathias", Age = 36, Children = 2 };
    Person person2 = new Person() { Name = "Anna", Age = 35, Children = 2 };
    Person person3 = new Person() { Name = "Emil", Age = 4, Children = 0 };            

    List<Person> persons = new List<Person>();
    persons.Add(person1);
    persons.Add(person2);

    RuleEngine.RuleEngine ruleEngine = new RuleEngine.RuleEngine();
    var ruleFunc =
        ruleEngine.CompileRule<Person>("Name", Operator.FoundIn, persons);
    var result = ruleFunc(person1);

    Rule<Person> rule = new Rule<Person>("Name", Operator.NotFoundIn, persons);
    var ruleFuncRule =
        ruleEngine.CompileRule<Person>(rule);

    var ruleFuncRuleResult = ruleFuncRule(person3);
    Assert.AreEqual(result, true); 
    Assert.AreEqual(ruleFuncRuleResult, false);
}

To implement that operator i had build a expression tree that is more complex that the simple one for Equal, Unequal, SmallerThen etc. Here is the code that builds the expression tree to check if a person with a given attribute is in a list of persons.

public Tuple<Expression, 
ParameterExpression> BuildExpression<T>(string propertyName, Operator ruleOperator, 
    ParameterExpression parameterExpression, List<T> values)
{                    
    ParameterExpression listExpression = Expression.Parameter(typeof(List<T>));
    ParameterExpression counterExpression = 
Expression.Parameter(typeof(int));
    ParameterExpression toExpression = Expression.Parameter(typeof(int));
    ParameterExpression arrayExpression = Expression.Parameter(typeof(T[]));
    ParameterExpression valueExpression = Expression.Parameter(typeof(T));
    ParameterExpression checkExpression = Expression.Parameter(typeof(T));
    ParameterExpression returnExpression = 
Expression.Parameter(typeof(bool));
    MemberExpression memberExpression = MemberExpression.Property(parameterExpression, propertyName);
    Expression expression = memberExpression.Expression;
    var type = memberExpression.Type;
    ParameterExpression propertyExpression = Expression.Parameter(type);
    ParameterExpression localPropertyExpression = Expression.Parameter(type);

    LabelTarget breakLabel = Expression.Label();
    PropertyInfo result = typeof(List<T>).GetProperty("Count");
    MethodInfo toArray = typeof(List<T>).GetMethod("ToArray");
    var toArrayName = toArray.Name;
    MethodInfo getGetMethod = result.GetGetMethod();
    ConstantExpression constantExpression = Expression.Constant(true);
    if (ruleOperator == Operator.NotFoundIn)
    {
        constantExpression = Expression.Constant(false);
    }
    Expression loop = Expression.Block(
        new ParameterExpression[] { 
toExpression, arrayExpression, valueExpression, counterExpression, 
        returnExpression, propertyExpression, localPropertyExpression, listExpression },
        Expression.Assign(listExpression, Expression.Constant(values)),
        Expression.Assign(toExpression, Expression.Call(listExpression, getGetMethod)),
        Expression.Assign(arrayExpression, Expression.Call(listExpression, toArray)),
        Expression.Assign(propertyExpression, MemberExpression.Property(checkExpression, propertyName)),
        Expression.Loop(
            Expression.IfThenElse(
                Expression.LessThan(counterExpression, toExpression),
                Expression.Block(
                    Expression.Assign(valueExpression, 
Expression.ArrayAccess(arrayExpression, counterExpression)),
                    Expression.Assign(localPropertyExpression, 
Expression.Property(valueExpression, propertyName)),
                    Expression.IfThen(
                        Expression.Equal(propertyExpression, localPropertyExpression),
                        Expression.Block(Expression.Assign(returnExpression, constantExpression),
                            Expression.Break(breakLabel))),
                    Expression.Assign(
Expression.ArrayAccess(arrayExpression, counterExpression), checkExpression),
                    Expression.PostIncrementAssign(counterExpression)),
                Expression.Break(breakLabel)
                ), breakLabel
            ),
            Expression.And(returnExpression, constantExpression)
        );
    return new Tuple<Expression, ParameterExpression>(Expression.Block(loop), checkExpression);
}

This code builds a loop that enumerates a list of objects and checks a specified property (localPropertyExpression specified by propertyName) has the same value as the propertyExpression. If the values are the same the returnExpression is set to true. (if it is the NotFoundIn operator it is set to false). The CompileRule call looks the following:

public Func<T, bool> CompileRule<T>(string propertyName, 
    Operator ruleOperator, List<T> values)
{
    ExpressionBuilder expressionBuilder = new ExpressionBuilder();
    var param = Expression.Parameter(typeof(T));
    Tuple<Expression, ParameterExpression> expression =
        expressionBuilder.BuildExpression<T>(propertyName, ruleOperator, param, values);
    Func<T, bool> compiledExpression = Expression.Lambda<Func<T, bool>>(
        expression.Item1, expression.Item2).Compile();
    return compiledExpression;
}

The differnece to all the other CompileRule methodes is that it takes a list of values. That list of values becomes iterated in the expression tree.

The second feature i was asked for by Mike is that he needed to call a method at the person object if a specific  property of the person has a specific value. The problem was that he needed that in the expression evaluator string. The following code shows what he needed.

var tuple = evaluator.Evaluate<Person>(
                " (Age < 10) then SetCanReceiveBenefits(true) else SetCancelBenefits(true) ");

To check if the evaluation works correct i have added two methodes (SetCanReceiveBenefits and SetCancelBenefits) to the person object.

public class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
    public int Children { get; set; }
    public bool Married { get; set; }
    public DateTime Birthdate { get; set; }
    public Adresse Adresse_ { get; set; }
    public bool ReceiveBenefits { get; set; }
    public bool CancelBenefits { get; set; }
    public void SetCanReceiveBenefits(bool receiveBenefits)
    {
        ReceiveBenefits = receiveBenefits;
    }
    public void SetCancelBenefits(bool cancelBenefits)
    {
        CancelBenefits = cancelBenefits;
    }
    private List<Adresse> adresses = new List<Adresse>();
    public List<Adresse> Adresses_ 
    { 
        get { return adresses; } 
        set { adresses = value; } 
    }
}

After that i had to change the lexer and the parser of the evaluation evaluator to handle the then and else keyword. Here is the complete test that shows how to use the then and else keyword.

[TestMethod]
public void SimpleExpressionEvaluatorWithThenMethod()
{
    Person person1 = new Person()
    {
        Name = "Mathias",
        Age = 36,
        Children = 2,
        Married = true,
        Birthdate = new DateTime(1976, 5, 9),
        CancelBenefits = false,
        ReceiveBenefits = false
    };            
    Evaluator evaluator = new Evaluator();
    bool result = evaluator.Evaluate(
        " (Age > 10) then SetCanReceiveBenefits(true) ", person1);
    Assert.AreEqual(person1.ReceiveBenefits, true);
}

Here is the test that shows how the else keyword works.

[TestMethod]
public void SimpleExpressionPreEvaluatorWithThenAndElseMethod()
{
    Person person1 = new Person()
    {
        Name = "Mathias",
        Age = 36,
        Children = 2,
        Married = true,
        Birthdate = new DateTime(1976, 5, 9),
        CancelBenefits = false,
        ReceiveBenefits = false
    };
    Evaluator evaluator = new Evaluator();
    bool result = evaluator.Evaluate(
         " (Age < 10) then SetCanReceiveBenefits(true) else SetCancelBenefits(true) ", person1);
    Assert.AreEqual(person1.CancelBenefits, true);
}

Mike also wrote that he needs the rule engine to work with many objects and asked if it is possible that the rule engine could preprocess the evaluation of the expression. So i splitted the evaluation process and added the PreEvalute method to preprocess the evaluation of the evaluation string and the building of the symbol table. The ExecuteEvaluate method takes the prepocessed abstract syntax tree and the symbol table and does only the evaluation with the given object. Her is a test that shows that preprocessing step.

[TestMethod]
public void SimpleExpressionPreEvaluatorWithThenElseMethod()
{
    Person person1 = new Person()
    {
        Name = "Mathias",
        Age = 36,
        Children = 2,
        Married = true,
        Birthdate = new DateTime(1976, 5, 9),
        CancelBenefits = false,
        ReceiveBenefits = false
    };
    Person person2 = new Person()
    {
        Name = "Anna",
        Age = 32,
        Children = 2,
        Married = false,
        Birthdate = new DateTime(2002, 2, 2),
        CancelBenefits = false,
        ReceiveBenefits = false
    };
    Evaluator evaluator = new Evaluator();
    var tuple = evaluator.PreEvaluate(
        " (Age < 10) then SetCanReceiveBenefits(true) else SetCancelBenefits(true) ");
    evaluator.ExecuteEvaluate(tuple, person1);
    evaluator.ExecuteEvaluate(tuple, person2);
    Assert.AreEqual(person1.CancelBenefits, true);
    Assert.AreEqual(person2.CancelBenefits, true);
}

If you use rule engine in a real project that could save a lot of time because the evaluation needs some time and repeats over and over again if you use the normal evaluate method.

The third feature i was asked for by Damian, and he needed to check if a specific property is null. So i implemented the is null operator. The problem is that in c# value types like int can not take null so this operator works only correct with strings. The following test shows how the is null operator works.

[TestMethod]
public void SimpleExpressionStringIsNullMethod()
{            
    Person person2 = new Person()
    {
        Name = null,
        Age = 32,
        Children = 2,
        Married = false,
        Birthdate = new DateTime(2002, 2, 2),
        CancelBenefits = false,
        ReceiveBenefits = false
    };
    Evaluator evaluator = new Evaluator();
    var result = evaluator.Evaluate(
        " Name is null ", person2);
    Assert.AreEqual(result, true);            
}

So if you want to use the rule engine in real world projects i hope that helps to check all rules you have to check.


Building a rule engine in c# (part 4: extending the rule engine to evaluate defined expressions)

In the first three posts of building a rule engine in c# building a rule engine in c#, building a rule engine in c# (part 2: extending the rule engine to handle collections), building a rule engine in c# (part 3: extending the rule engine to handle aggregations of collections) the definition of the rules are very basic and did not look very clear. So i decided to implement an expression evaluator. With this expression evaluator the definition of the rules becomes much clearer. I will show the difference in the next three pictures. The first one shows the definition of the rules how i described it in the past three posts.

ProcessingEngineDatabase

This second picture shows the definition with a expression evaluator.

ComplexProcessingRule

If we use a expression evaluator we can also use logical combinators (and, or) to combine the defined rules. The third picture shows how the processing rules would look like if they are combined.

ComplexProcessingRuleCombinator2

The problem with that processing rules is that in the first three post i used expression trees to generate the rules but i had the seperate parts of the rules and so i needed no parser. Now we have to develop a parser that parses the expression and an evaluator that checks the overtaken object against the parsed expression. In this post i will show how to use the expression evaluator i posted at codeplex (https://simpleexpeval.codeplex.com/) to validate a given object against the defined rule. In the additional blog post implementing an expression evaluator in c# i describes how the expression evaluator works. But in this post i will describe how to use it to define the rules you need to check your object again. The expression evaluator support the following operators:

  • open bracket ‘(‘ and close bracket ‘)’
  • addition ‘+’
  • subtraction ‘-‘
  • multiblication ‘*’
  • division ‘/’
  • modulo ‘%’
  • equality ‘=’
  • unequality ‘!=’
  • bigger than ‘>’
  • bigger than or equal ‘>=’
  • smaller than ‘<‘
  • smaller than or equal ‘<=’
  • logical and ‘&&’
  • logical or ‘||’

and the following data types:

  • integer ’10’
  • double ‘10.2’
  • string ‘”test”‘
  • boolean ‘true’ or ‘false’

This is a example how to use the expression evaluator with a defined person that is evaluated against a rule. That is the definition of the person class:

public class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
    public int Children { get; set; }
    public bool Married { get; set; }
}

Now the defined rule text (” (Children = 2 && Married = true) || Age > 36 “) is evaluated against the defined person object.

Person person = new Person() { Name = "Mathias", Age = 36, Children = 2, Married = true };
RuleLoader ruleLoader = new RuleLoader();
Rule processingRule = ruleLoader.LoadProcessingRule(5);
//processingRule.ProcessingRule = " (Children = 2 && Married = true) || Age > 36 ";
Evaluator evaluator = new Evaluator();
var evaluatorResult = evaluator.Evaluate<Person>(ruleText, person);

The evaluatorResult is true because the person object has two children and is married. Here is a second example that shows that it is possible to use properties at any possition in the rule text.

Person person = new Person() { Name = "Mathias", Age = 36, Children = 2, Married = true };
RuleLoader ruleLoader = new RuleLoader();
Rule processingRule = ruleLoader.LoadProcessingRule(5);
//processingRule.ProcessingRule = " Name != 'test' && Children <= Age / 20 "; 
Evaluator evaluator = new Evaluator(); 
var evaluatorResult = evaluator.Evaluate<Person>(ruleText, person);

The evaluatorResult is also true because Age / 20 is smaller than Children and the name is unequal ‘test’. If you want to use the expression evaluation engine you can download it from codeplex (https://simpleexpeval.codeplex.com/) and add a reference in your visual studio project. Then you can use the Evaluator class to evaluate the defined rule text against an overtaken object. In the blog post implementing an expression evaluator in c# i describe the implementation of the expression evaluator and in the post building a rule engine in c# (part 5: bringing it all together) i try to give an overview of the usage of the ruleengine.codeplex.com project.


Building a rule engine in c# (part 3: extending the rule engine to handle aggregations of collections)

In had a comment on my post about building a rule engine in c#. The question in this comment was how to handle aggregations within the rule engine. In this post i try to give one example how to handle aggregations. I will show a possible way to include sum and average in the rule engine and to look if the aggregated property of the property of a collection of objects corresponds one or many of the defined rules. I wrote two post about the topic building a rule engine in c# and building a rule engine in c# (part 2: extending the rule engine to handle collections). Now i will extend the RuleValidator i implemented in the second post with two methods that can handle the sum and average. This are the rules in the database:

ProcessingEngineDatabase

Now i have a list of Person objects and want to know if the sum of all children are greater than zero and the sum of the age of all Person objects is Less than or equal 50. So in that case the result is false because the second rule (Age <= 50) failes.

Person person1 = new Person() { Name = "Mathias", Age = 35, Children = 2 };
Person person2 = new Person() { Name = "Anna", Age = 32, Children = 2 };
RuleValidator ruleValidator = new RuleValidator();
var sum = ruleValidator.ValidateRulesSum(
    new Person[] { person1, person2 }, 
    new Rule[] { firstRule, secondRule });

The ValidateRulesSum method call sums up the values of the property that is relevant for the overtaken rule and then checks the rule with the calculated sum.. To do so i need some reflection and the dynamic keyword to handle different types. (Int32, Double etc.). So thats how the ValidateRulesSum and the ValidateRulesAvg methodes look like.

public bool ValidateRulesSum<T>(IEnumerable<T> values, IEnumerable<Rule> rules)
{
    foreach (var rule in rules)
    {
        // necessary to create the type dynamic so i could use the + operator to 
        // build the sum on an Int32 or Double or Decimal
        dynamic sum = Activator.CreateInstance(
            values.GetType().GetElementType().GetProperty(rule.PropertyName).PropertyType);
        foreach (var value in values)
        {
            dynamic innerValue = value.GetType().
                GetProperty(rule.PropertyName).GetValue(value, null);
            // creating the sum
            sum += innerValue;
        }
        // building the Func
        dynamic func = BuildGenericFunction(rule, sum);
        // checking the rule Func with the sum value
        if (!func(sum))
            return false;                
    }
    return true;
}
public bool ValidateRuleAvg<T>(IEnumerable<T> values, IEnumerable<Rule> rules)
{
    foreach (var rule in rules)
    {
        dynamic sum = Activator.CreateInstance(values.GetType().
            GetElementType().GetProperty(rule.PropertyName).PropertyType);
        var counter = 0;
        foreach (var value in values)
        {
            dynamic innerValue = value.GetType().
                GetProperty(rule.PropertyName).GetValue(value, null);
            sum += innerValue;
            counter++;
        }
        dynamic avg = sum / counter;
        dynamic func = BuildGenericFunction(rule, avg);
        if (!func(avg))
            return false;
    }
    return true;
}
private object BuildGenericFunction(Rule rule, object sum)
{
    ExpressionBuilder expressionBuilder = new ExpressionBuilder();
    System.Type specificType = sum.GetType();
    var param = Expression.Parameter(specificType);
    Expression expression = expressionBuilder.
        BuildExpression(specificType, rule.Operator_, rule.Value, param);
    // creates the generic type so i can make a call with the type of 
    // the property to the BuildLambdaFunc function
    MethodInfo method = this.GetType().GetMethod("BuildLambdaFunc", 
        BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
    MethodInfo generic = method.MakeGenericMethod(specificType);
    object func = generic.Invoke(this, new object[] { expression, param });
    return func;
}

private Func<T, bool> BuildLambdaFunc<T>(
    Expression expression, ParameterExpression param)
{
    // building the lambda function
    Func<T, bool> func = Expression.Lambda<Func<T, bool>>
        (expression, param).Compile();
    return func;
}

The code is straight fourward but to get out the type of the property of the Person object that is defined in the Rule (e.g. Age) i need the MakeGenericMethod method of the MethodInfo type and that i have to use the Invoke method to invoke the dynamic created method. That is necessary because the BuildLambdaFunc method has a generic type T definied and i need to overtake the type of the property of the Person object (e.g. Int32 for Age). So with the reflection method MakeGenericMethod i can build the method with the generic type T. I dont need to know the type at compile time i can find it out at runtime. In the fourth part of this blog series i write about implementing an expression evaluator to define more complex expressions. (Building a rule engine in c# (part 4: extending the rule engine to evaluate defined expressions)) and in the fifth part building a rule engine in c# (part 5: bringing it all together) i give an overview about the usage of the ruleengine.codeplex.com project i created to bring the code parts in that post series together.


Building a rule engine in c# (part 2: extending the rule engine to handle collections)

In my blog post about building a rule engine in c# i wrote about the core implementation of a rule engine. In this seconde post i will extend the rule engine so that it can handle collections of rules and collections of items to validate against the rules. To do so i have to extend the RuleEngine class and i have to introduce a RuleValidator class. With the extension of the RuleEngine the following code is possible:

ProcessingEngineDatabase

RuleLoader ruleLoader = new RuleLoader();
Rule firstRule = ruleLoader.Load(1);
Rule secondRule = ruleLoader.Load(2);
Rule thirdRule = ruleLoader.Load(3);

RuleEngine ruleEngine = new RuleEngine();
var ruleFuncs = ruleEngine.CombineRules<Person>(
    new Rule[] { firstRule, secondRule, thirdRule });

That means I load first, second and third rule and combine them to a array of rules. To do so i implemented the CombineRules method in the RuleEngine class.

public Func<T, bool>[] CombineRules<T>(Rule[] rules)
{
    List<Func<T, bool>> list = new List<Func<T, bool>>();
    foreach (Rule rule in rules)
    {
        if (string.IsNullOrEmpty(rule.PropertyName))
        {
            ExpressionBuilder expressionBuilder = new ExpressionBuilder();
            var param = Expression.Parameter(typeof(T));
            Expression expression = expressionBuilder.BuildExpression<T>(rule.Operator_, rule.Value, param);
            Func<T, bool> func = Expression.Lambda<Func<T, bool>>(expression, param).Compile();
            list.Add(func);
        }
        else
        {
            ExpressionBuilder expressionBuilder = new ExpressionBuilder();
            var param = Expression.Parameter(typeof(T));
            Expression expression = expressionBuilder.BuildExpression<T>(rule.PropertyName, rule.Operator_, rule.Value, param);
            Func<T, bool> func = Expression.Lambda<Func<T, bool>>(expression, param).Compile();
            list.Add(func);
        }
    }
    return list.ToArray();
}

The i use the new RuleValidator to validate one or a collection of objects against that defined rules.

RuleValidator ruleValidator = new RuleValidator();
bool result = ruleValidator.ValidateRulesAll(person, ruleFuncs);
result = ruleValidator.ValidateRulesAny(person, ruleFuncs);

As we see there are two methodes to validate the person object against the rules. The ValidateRulesAll method returns true if all rules are passed by the overtaken person object. The ValidateRulesAny method return true if any rule is passed by the overtaken person object. It is also possible to validate not only one person object but a collection of person objects.

Person person1 = new Person() { Name = "Mathias", Age = 36, Children = 2 };
Person person2 = new Person() { Name = "Anna", Age = 33, Children = 2 };
bool result = ruleValidator.ValidateRulesAll(new Person[] { person1, person2 }, ruleFuncs);
result = ruleValidator.ValidateRulesAny(new Person[] { person1, person2 }, ruleFuncs);

In this case both methodes (ValidateRulesAll and ValidateRulesAny) return true because the test persons both pass all three rules. The implementation of the RuleValidator class is very simple. It is just a foreach loop that calls the overtaken rules with the overtaken values. In the ValidateRulesAll method it checks if all rules are passed and then returns true, in the ValidateRulesAny it checks one rule after the other and if one rule is passed it returns true.

public class RuleValidator
{
    public bool ValidateRulesAll<T>(T value, Func<T, bool>[] rules)
    {
        foreach (var rule in rules)
        {
            if (!rule(value))
                return false;
        }
        return true;
    }

    public bool ValidateRulesAny<T>(T value, Func<T, bool>[] rules)
    {
        foreach (var rule in rules)
        {
            if (rule(value))
                return true;
        }
        return false;
    }

    public bool ValidateRulesAll<T>(T[] values, Func<T, bool>[] rules)
    {
        foreach (var value in values)
        {
            foreach (var rule in rules)
            {
                if (!rule(value))
                    return false;
            }
        }
        return true;
    }

    public bool ValidateRulesAny<T>(T[] values, Func<T, bool>[] rules)
    {
        foreach (var value in values)
        {
            bool validated = false;
            foreach (var rule in rules)
            {
                if (rule(value))
                {
                    validated = true;
                    break;
                }
            }
            if (!validated)
                return false;
        }
        return true;
    }
}

In this third part of the post series called Building a rule engine in c# (part 3: extending the rule engine to handle aggregations of collections) i extend the rule engine to handle aggregation for collections. In the fourth part of this blog series i write about implementing an expression evaluator to define more complex expressions Building a rule engine in c# (part 4: extending the rule engine to evaluate defined expressions) and in the fifth part building a rule engine in c# (part 5: bringing it all together) i give an overview about the usage of the ruleengine.codeplex.com project i created to bring the code parts in that post series together.


Building a rule engine in c#

In my current project in work i needed a simple rule engine that processes rules that are saved in the database. In the Database i have the following table:

The column Property stores the name of the property of the overtaken class. The column Operator stores the logical operator which is used to evaluate the rule and the column Value stores the constant to evaluate against. To try this rules we have the Person class.

    public class Person
    {
        public string Name { get; set; }
        public int Age { get; set; }
        public int Children { get; set; }
    }

This class has the properties Name, Age and Children. The rule class stores the rules that are defiened in the database table.

    public class Rule
    {
        private bool propertySet = false;
        public string PropertyName { get; set; }
        public Operator Operator_ { get; set; }
        public object Value { get; set; }

        public Rule(Operator operator_, object value)
        {
            this.Operator_ = operator_;
            this.Value = value;
        }

        public Rule(string propertyName, Operator operator_, object value)
        {
            this.Operator_ = operator_;
            this.Value = value;
            this.PropertyName = propertyName;
            if(!string.IsNullOrEmpty(propertyName))
                this.propertySet = true;
        }
    }

The RuleLoader class loads the rules from the database and stores it in Rule objects. This is the code to load the rules from the database.

            RuleLoader ruleLoader = new RuleLoader();
            Rule firstRule = ruleLoader.Load(1);
            Rule secondRule = ruleLoader.Load(2);
            Rule thirdRule = ruleLoader.Load(3);

Now we have the rules and what we need is a Person to apply the rules to.

Person person = new Person() { Name = "Mathias", Age = 35, Children = 2 };

Now we will define the rule engine that evaluates the values of the property of the Person objects against the definied rules from the database. To do so we need some reflection and some objects from the System.Linq.Expressions namespace. This is the RuleEngine class that generates a Func that we use to evaluate the overtaken rule.

    public class RuleEngine
    {
        public Func<T, bool> CompileRule<T>(Rule rule)
        {
            if (string.IsNullOrEmpty(rule.PropertyName))
            {
                ExpressionBuilder expressionBuilder = new ExpressionBuilder();
                var param = Expression.Parameter(typeof(T));
                Expression expression = 
                    expressionBuilder.BuildExpression<T>(rule.Operator_, rule.Value, param);
                Func<T, bool> func = 
                    Expression.Lambda<Func<T, bool>>(expression, param).Compile();
                return func;
            }
            else
            {
                ExpressionBuilder expressionBuilder = new ExpressionBuilder();
                var param = Expression.Parameter(typeof(T));
                Expression expression = 
                    expressionBuilder.BuildExpression<T>(
                    rule.PropertyName, rule.Operator_, rule.Value, param);
                Func<T, bool> func = 
                    Expression.Lambda<Func<T, bool>>(expression, param).Compile();
                return func;
            }
        }
    }

The RuleEngine class uses the ExpressionBuilder class to build the Expression and compiles it to a lambda expression. This lambda expression does the actual work when a rule is evaluated.

    public class ExpressionBuilder
    {
        public Expression BuildExpression<T>(
            Operator ruleOperator, object value, ParameterExpression parameterExpression)
        {
            ExpressionType expressionType = new ExpressionType();
            var leftOperand = parameterExpression;
            var rightOperand = 
                Expression.Constant(Convert.ChangeType(value, typeof(T)));
            var expressionTypeValue = 
                (ExpressionType)expressionType.GetType().GetField(
                Enum.GetName(typeof(Operator), ruleOperator)).GetValue(ruleOperator);
            var binaryExpression = 
                Expression.MakeBinary(expressionTypeValue, leftOperand, rightOperand);
            return binaryExpression;
        }

        public Expression BuildExpression<T>(
            string propertyName, Operator ruleOperator, object value, 
            ParameterExpression parameterExpression)
        {
            ExpressionType expressionType = new ExpressionType();
            var leftOperand = MemberExpression.Property(parameterExpression, propertyName);
            var rightOperand = Expression.Constant(Convert.ChangeType(value, value.GetType()));
            FieldInfo fieldInfo = 
                expressionType.GetType().GetField(Enum.GetName(typeof(Operator), ruleOperator));
            var expressionTypeValue = (ExpressionType)fieldInfo.GetValue(ruleOperator);
            var binaryExpression = 
                Expression.MakeBinary(expressionTypeValue, leftOperand, rightOperand);
            return binaryExpression;
        }
    }

Here we see the usage of the RuleEngine class. We call the CompileResult method and get back a Func that evaluates us the overtaken parameter (in this case of type Person).

     RuleEngine ruleEngine = new RuleEngine();
     var firstRuleFunc = ruleEngine.CompileRule<Person>(firstRule);
     var secondRuleFunc = ruleEngine.CompileRule<Person>(secondRule);
     var thirdRuleFunc = ruleEngine.CompileRule<Person>(thirdRule);
     var result = firstRuleFunc(person) &&
         secondRuleFunc(person) && thirdRuleFunc(person);

So we know that the Person object

( Person person = new Person() { Name = "Mathias", Age = 35, Children = 2 }; )

passes all the defiend rules from the database.

In the second part of this post i will extend the rule engine to handle collections:
Building a rule engine in c# (part 2: extending the rule engine to handle collections) In this third part of the post series called Building a rule engine in c# (part 3: extending the rule engine to handle aggregations of collections) i extend the rule engine to handle aggregation for collections. In the fourth part of this blog series i write about implementing an expression evaluator to define more complex expressions Building a rule engine in c# (part 4: extending the rule engine to evaluate defined expressions) and in the fifth part building a rule engine in c# (part 5: bringing it all together) i give an overview about the usage of the ruleengine.codeplex.com project i created to bring the code parts in that post series together.