Rule Engine

Getting Started
A fast and reliable .NET Rules Engine with extensive Dynamic expression support - microsoft/RulesEngine
https://github.com/microsoft/RulesEngine/wiki/Getting-Started

  1. To install this library, please download the latest version of NuGet Package from nuget.org and refer it into your project.
  1. Initiate the instance of Rules Engine as mentioned in Initiating the Rules Engine.
  1. Once done, the rules can be executed using any of the overloaded methods as explained in IRulesEngine section. It returns the list of RuleResultTree which can be used in any way the user wants to.
  1. The success or failure events can be defined as explained in the Success/Failure section.
    • Based on the rules and input the success or failure event can be triggered.

Objects

Rules

A lambda expression that can be executed.

Rules Schema

The schema for storing those rules.

[
  {
    "WorkflowName": "Discount",
    "Rules": [
      {
        "RuleName": "GiveDiscount10",
        "SuccessEvent": "10",
        "ErrorMessage": "One or more adjust rules failed.",
        "ErrorType": "Error",
        "RuleExpressionType": "LambdaExpression",
        "Expression": "input1.country == \"india\" AND input1.loyalityFactor <= 2 AND input1.totalPurchasesToDate >= 5000 AND input2.totalOrders > 2 AND input3.noOfVisitsPerMonth > 2"
      },
    ]
  }
]

ReSettings

Allows you to use custom functions in the rule.

First a class to hold custom functions.

using System;
using System.Linq;

namespace RE.HelperFunctions
{
    public static class Utils
    {
        public static bool CheckContains(string check, string valList)
        {
            if (String.IsNullOrEmpty(check) || String.IsNullOrEmpty(valList))
                return false;

            var list = valList.Split(',').ToList();
            return list.Contains(check);
        }
    }
}

Second use the method in the lambda expression like this.

"Expression": "Utils.CheckContains(input1.country, \"india,usa,canada,France\") == true"

Third register the rule engine class with the custom types.

var reSettingsWithCustomTypes = new ReSettings { CustomTypes = new Type[] { typeof(Utils) } };
new RulesEngine.RulesEngine(workflowRules.ToArray(), null, reSettingsWithCustomTypes);

RuleParameter

In your expressions you have to get the inputs by names like input1.country. But you might want to use better names like transaction.country. The parameter class allows you to change the name of the inputs.

var ruleParameter = new RuleParameter(
    "transaction",
    input);

LocalParams

Allows you to break a single large expression down into smaller expressions.

{
  "name": "allow_access_if_all_mandatory_trainings_are_done_or_access_isSecure",
  "errorMessage": "Please complete all your training(s) to get access to this content or access it from a secure domain/location.",
  "errorType": "Error",
  "localParams": [
    {
      "name": "completedSecurityTrainings",
      "expression": "MasterSecurityComplainceTrainings.Where(Status.Equals(\"Completed\", StringComparison.InvariantCultureIgnoreCase))"
    },
    {
      "name": "completedProjectTrainings",
      "expression": "MasterProjectComplainceTrainings.Where(Status.Equals(\"Completed\", StringComparison.InvariantCultureIgnoreCase))"
    },
    {
      "name": "isRequestAccessSecured",
      "expression": "UserRequestDetails.Location.Country == \"India\" ? ((UserRequestDetails.Location.City == \"Bangalore\" && UserRequestDetails.Domain=\"xxxx\")? true : false):false"
    }
  ],
  "expression": "(completedSecurityTrainings.Any() && completedProjectTrainings.Any()) || isRequestAccessSecured "
}

RuleResultTree

Output of the rule engine. It holds the following.

IRuleEngine

Interface for executing rules.

List<RuleResultTree> ExecuteRule(string workflowName, IEnumerable<dynamic> input, object[] otherInputs);
List<RuleResultTree> ExecuteRule(string workflowName, object[] inputs);
List<RuleResultTree> ExecuteRule(string workflowName, object input);
List<RuleResultTree> ExecuteRule(string workflowName, RuleParameter[] ruleParams);

Init RuleEngine

public RulesEngine(string[] jsonConfig,ReSettings reSettings = null) 
public RulesEngine(WorkflowRules[] workflowRules, ReSettings reSettings = null)

Events

OnSuccess

Called when one or more rules passed.

List<RuleResultTree> resultList = bre.ExecuteRule("Discount", inputs);

resultList.OnSuccess((eventName) =>
{
discountOffered = $"Discount offered is {eventName} % over MRP.";
});

OnFail

Called when all rules failed.

List<RuleResultTree> resultList = bre.ExecuteRule("Discount", inputs);
resultList.OnFail(() =>
{
discountOffered = "The user is not eligible for any discount.";
});