Tuesday, June 28, 2011

Build XML based Business Rule Engine in .NET 4 – Post 3 (write runtime condition predicate)

It is continuation of first post - << click here to read
and second post - < click here to read

Dynamicity is of great advantage. First of all let us move forward step wise, define delegate to a separate method;
rule.AddCondtion(po => po.NetProductPrice >= 0);
should tends to

public static Predicate<PriceObject> IsPriceGreaterOrEqualToZero()
    return delegate(PriceObject po) { return po.NetProductPrice >= 0; };

Let us consider even more generic function to write. Point is every condition returns  Predicate<PriceObject> and internally the condition result is a Boolean variable (true/false). Why not create runtime generic delegate to handle Equals operator for example. We will make it compatible to other operators later.

public static Predicate<T> GetConditiPredicate<T>(string fieldName, string operatorName, string value)
    Type itemType = typeof(T);
    ParameterExpression predParam = Expression.Parameter(itemType, "po");
    PropertyInfo propertyInfo = itemType.GetProperty(fieldName);
    Expression left = Expression.Property(predParam, propertyInfo);
    Expression right = Expression.Constant(ObjTypeConverter.ChangeType(value, propertyInfo.PropertyType), propertyInfo.PropertyType);
    Expression equality = Expression.GreaterThanOrEqual(left, right);
    Func<T, bool> function = (Func<T, bool>)Expression.Lambda(equality, new[] { predParam }).Compile();
    return new Predicate<T>(function);

And caller can deliver a call like this

rule.AddCondtion(Dynamic.GetConditiPredicate<PriceObject>("DRM", "Equals", "2"));

Well compile and see if it works fine. It should :)

Now let us replace the statement with more general one….
//Expression equality = Expression.GreaterThanOrEqual(left, right);
Expression result = GetExpression(operatorName, left, right);
Func<T, bool> function = (Func<T, bool>)Expression.Lambda(result, new[] { predParam }).Compile();


public static Expression GetExpression(string operatorName, Expression left, Expression right)
    Expression result = null;
    switch (operatorName.ToLower())
        case "equals":
            result = Expression.Equal(left, right);
        case "greaterorequal":
            result = Expression.GreaterThanOrEqual(left, right);
        case "lessorequal":
            result = Expression.LessThanOrEqual(left, right);
        case "greaterthan":
            result = Expression.GreaterThan(left, right);
        case "lessthan":
            result = Expression.LessThan(left, right);
        case "add":
            result = Expression.Add(left, right);
        case "subtract":
            result = Expression.Subtract(left, right);
        case "multiply":
            result = Expression.Multiply(left, right);
        case "divide":
            result = Expression.Divide(left, right);
            throw new Exception("Unknown Operator Name");
    return result;
 This was simple to handle isolated conditions. How to handle Actions that may depend one another give us new dimension.

If want to play with Rule Engine source code - I extracted from my business case for demo purpose. download from skydrive. (FileName: ConfigurableRuleEngine.zip)
Comments please   


  1. Nice Post. Thanks for sharing this.
    Can I have the full sample project (source code) please?

    1. Done; Sorry for delay. I added the link 'download from skydrive' FileName: ConfigurableRuleEngine.zip - in the bottom of this post.


  2. As Salamu Alaikum Bhai Basharat ,

    i am from Delhi,

    i was using your code ,
    and i found that it works for decimal types only
    if a DateTime Parameter in priceobject is used it does not support it and it is obvious because you have used decimal types for the engine in action ....

    can you give a solution for all Data types ??

    JazakAllahu Khair

    Hope All is good in Pakistan InshAllah !!!

  3. And Bhai can u please give a application using mvc3 with aspx view engine ......

    JazakAllahu Khair

  4. Hi Bashrat.Nice article.but i am unable to download the file from the above link.Also what is the LogicalOperation Operation .is the custom developed class(LogicalOperation) or predefined one,please confirm

  5. Great & helpful article. I was trying to figure out how to define a custom action whereby it is a custom method I would like to invoke. Do you have an example of such a call?