Expression Trees 2: Creating a Business Rule Engine

In the previous post, I covered the basics of expression trees, including their structure and how to create them in .NET. Now, let’s dive into a real-world example: building a simple Business Rule Engine (BRE) using expression trees. This engine will apply discount rules based on certain conditions.

Scenario: Discount Calculation

Imagine you are working on an e-commerce platform, and you need to implement a business rule engine (BRE) system, and one of its features is to calculate discounts based on various business rules. These rules might include conditions like:

  • If the customer is a premium member AND the order amount is greater than $100, apply a 10% discount.
  • If the order contains more than 5 items OR the order amount is greater than $200, apply a 5% discount.

Building the Business Rule Engine

We’ll build a modular Business Rule Engine that evaluates these conditions dynamically using expression trees. (using expressions, we can make cleaner, more maintainable, and performant code)

Step 1: Define the Data Model

First, let’s define our data model for orders and customers.

public class Order
{
    public decimal Amount { get; set; }
    public int ItemCount { get; set; }
    public bool IsPremiumMember { get; set; }
} 

Step 2: Define the Rule Structure

Next, we’ll define the structure for our discount rules.

public class DiscountRule
{
    public Expression<Func<Order, bool>> Condition { get; set; }
    public decimal DiscountPercentage { get; set; }
}

Step 3: Create the Rule Engine

We’ll create a class to manage and evaluate these rules.

public class RuleEngine
{
    private readonly List<DiscountRule> _rules = new List<DiscountRule>();

    public void AddRule(DiscountRule rule)
    {
        _rules.Add(rule);
    }

    public decimal CalculateDiscount(Order order)
    {
        foreach (var rule in _rules)
        {
            var compiledCondition = rule.Condition.Compile();
            if (compiledCondition(order))
            {
                return rule.DiscountPercentage;
            }
        }
        return 0;
    }
}

Step 4: Define the Discount Rules

Now let’s define our discount rules using expression trees.

using System;
using System.Linq.Expressions;

class Program
{
    static void Main()
    {
        var ruleEngine = new RuleEngine();

        // Rule 1: If the customer is a premium member AND the order amount is greater than $100, apply a 10% discount.
        var rule1 = new DiscountRule
        {
            Condition = order => order.IsPremiumMember && order.Amount > 100,
            DiscountPercentage = 10
        };

        // Rule 2: If the order contains more than 5 items OR the order amount is greater than $200, apply a 5% discount.
        var rule2 = new DiscountRule
        {
            Condition = order => order.ItemCount > 5 || order.Amount > 200,
            DiscountPercentage = 5
        };

        ruleEngine.AddRule(rule1);
        ruleEngine.AddRule(rule2);

        // Example order
        var order = new Order
        {
            Amount = 150,
            ItemCount = 3,
            IsPremiumMember = true
        };

        decimal discount = ruleEngine.CalculateDiscount(order);
        Console.WriteLine($"Discount: {discount}%"); // Output: Discount: 10%
    }
} 

Benefits of Using Expression Trees

  1. Flexibility: Easily define and modify business rules without changing the core logic.
  2. Dynamic Evaluation: Compile and evaluate conditions at runtime.
  3. Modularity: Add or remove rules as needed without affecting other parts of the system.
  4. Performance: A compiled code can be run faster

Conclusion

By leveraging expression trees, we can build a flexible and modular Business Rule Engine that dynamically evaluates complex conditions. This approach not only simplifies the implementation of business logic but also enhances maintainability and scalability.

Stay tuned!

Leave a Comment