Defining Rules

# Global parameters
Parameters:
  - Name: DemoDate
    Expression: DateTime.Now
  - Name: IsOldCar
    Expression: Auto.Age > 10
  - Name: HasRecentCollision
    Expression: Collisions.Any(c => c.VIN == Auto.VIN && c.Date > DemoDate.AddYears(-1))
Rules:
  - Id: rule_low_risk
    # Note expressions with boolean ! must be included in quotes because it's a reserved tag in YAML
    Condition: "!IsOldCar && !HasRecentCollision"
  - Id: rule_high_risk
    Condition: IsOldCar && HasRecentCollision
    Then: '"VIN: " + Auto.VIN + " High Risk"'
  - Id: rule_requires_high_risk
    DependsOn: [rule_high_risk]
    Condition: true
    Then: '"This rule only runs if rule_high_risk succeeds."'

Rules Anatomy

Dynamic Rules are defined by the object definitions in RulesEngine.Dynamic/Models. A set of YAML or JSON rules is simply a serialization of the DynamicRules C# type:

public class DynamicRules
{
    public virtual List<DynamicRuleParameter> Parameters { get; set; } = [];
    public virtual List<DynamicRule> Rules { get; set; } = [];
}

Let's review each feature with YAML.

Parameters -> (Name, Expression)

Global parameters are in scope by all rules and sub-rules. These must be at the top of your rule definitions. Name identifies the parameter. Expression is the C# that the parameter evaulates to. Use the name to refer to the parameter in other expressions.

Parameters:
  - Name: IsOldCar
    Expression: Auto.Age > 10
  - Name: HasRecentCollision
    Expression: Auto.CollisionDates.Any(d => d > DemoDate.AddYears(-1))

Rules -> (Id, Condition, Then, Parameters, DependsOn, Operator, Rules)

Id

Unique name of rule

Condition

C# expression that evaluates to a boolean

Then

C# expression that evaluates to an object added to an artifact if Condition is satisfied. Note the rules engine always generates an artifact for a succussful rule and artifacts can be accessed from code. The Then expression only adds an object to the artifact. See Using Rules for details.

Rules:
  - Id: rule_high_risk
    Condition: IsOldCar && HasRecentCollision
    Then: '"High Risk: VIN " + Auto.VIN'
  - Id: rule_low_risk
    Condition: "!IsOldCar && !HasRecentCollision"
    Then: "RiskUtils.FlagLowRisk(Auto.Make, Auto.Age)"

Parameters -> (Name, Expression)

Rule scoped parameters. Name should be unique for the given rule. If it matches a global parameter, it overrides the global value.

- Id: rule_critical_risk
    Parameters:
      - Name: RecentCollisionCount
        Expression: Auto.CollisionDates.Count(d => d > DemoDate.AddYears(-1))
    Condition: "!IsOldCar && HasRecentCollision"
    Then: '"Critical Review Needed: VIN:" + Auto.VIN + " Make:" + Auto.Make + " - Recent Collisions: " + RecentCollisionCount'

DependsOn

Value is an array of rule IDs that must all evaluate to true before this rule is evaluated. Rule IDs can reference other rules or sub-rules (including those from the same or different rule groups). The rules engine will throw an exception if a circular dependency is detected.

- Id: rule_high_risk_toyota
    DependsOn: [rule_high_risk]
    Condition: Auto.Make == "Toyota"
    Then: '"This rule only runs if Toyota and rule_high_risk succeeds."'

Rules

Subrules are nested rules within a parent rule. By default, all subrules must evaluate to true for the parent rule to succeed.

Rules:
  - Id: main_rule
    Rules: 
      - Id: sub_rule_1

You can control how subrules are combined by specifying the optional Operator parameter, which accepts 'AND' (default) or 'OR':

Rules:
  - Id: main_rule
    Operator: OR
    Rules: 
      - Id: sub_rule_1
      - Id: sub_rule_2