README updates related to EF (#190)

Basic Demo shown for code only solution

Co-authored-by: Alex Reich <Alex_Reich@mechanicsbank.com>
pull/195/head
Alex Reich 2021-07-28 00:13:19 -07:00 committed by GitHub
parent 9f898b703b
commit 4796cbfd70
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 126 additions and 27 deletions

View File

@ -12,8 +12,9 @@ Rules Engine is a library/NuGet package for abstracting business logic/rules/pol
To install this library, please download the latest version of [NuGet Package](https://www.nuget.org/packages/RulesEngine/) from [nuget.org](https://www.nuget.org/) and refer it into your project.
## How to use it
There are several ways to populate workflows for the Rules Engine as listed below.
You need to store the rules based on the [schema definition](https://github.com/microsoft/RulesEngine/blob/main/schema/workflowRules-schema.json) given and they can be stored in any store as deemed appropriate like Azure Blob Storage, Cosmos DB, Azure App Configuration, SQL Servers, file systems etc. The expressions are supposed to be a [lambda expressions](https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/statements-expressions-operators/lambda-expressions).
You need to store the rules based on the [schema definition](https://github.com/microsoft/RulesEngine/blob/main/schema/workflowRules-schema.json) given and they can be stored in any store as deemed appropriate like Azure Blob Storage, Cosmos DB, Azure App Configuration, [Entity Framework](https://github.com/microsoft/RulesEngine#entity-framework), SQL Servers, file systems etc. The expressions are supposed to be a [lambda expressions](https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/statements-expressions-operators/lambda-expressions).
An example rule could be -
```json
@ -52,7 +53,7 @@ Once done, the Rules Engine needs to execute the rules for a given input. It can
```c#
List<RuleResultTree> response = await rulesEngine.ExecuteAllRulesAsync(workflowName, input);
```
Here, *workflowName* is the name of the workflow, which is *Discount* in the above mentioned example. And *input* is the object which needs to be checked against the rules.
Here, *workflowName* is the name of the workflow, which is *Discount* in the above mentioned example. And *input* is the object which needs to be checked against the rules, which itself may consist of a list of class instances.
The *response* will contain a list of [*RuleResultTree*](https://github.com/microsoft/RulesEngine/wiki/Getting-Started#ruleresulttree) which gives information if a particular rule passed or failed.
@ -61,6 +62,36 @@ _Note: A detailed example showcasing how to use Rules Engine is explained in [Ge
_A demo app for the is available at [this location](https://github.com/microsoft/RulesEngine/tree/main/demo)._
### Basic
A simple example via code only is as follows:
```c#
List<Rule> rules = new List<Rule>();
Rule rule = new Rule();
rule.RuleName = "Test Rule";
rule.SuccessEvent = "Count is within tolerance.";
rule.ErrorMessage = "Over expected.";
rule.Expression = "count < 3";
rule.RuleExpressionType = RuleExpressionType.LambdaExpression;
rules.Add(rule);
workflowRule.Rules = rules;
workFlowRules.Add(workflowRule);
var bre = new RulesEngine.RulesEngine(workFlowRules.ToArray(), null);
```
### Entity Framework
Consuming Entity Framework and populating the Rules Engine is shown in the [EFDemo class](https://github.com/microsoft/RulesEngine/blob/main/demo/DemoApp/EFDemo.cs) with Workflow rules populating the array and passed to the Rules Engine, The Demo App includes an example [RulesEngineDemoContext](https://github.com/microsoft/RulesEngine/blob/main/demo/DemoApp.EFDataExample/RulesEngineDemoContext.cs) using SQLite and could be swapped out for another provider.
```c#
var wfr = db.WorkflowRules.Include(i => i.Rules).ThenInclude(i => i.Rules).ToArray();
var bre = new RulesEngine.RulesEngine(wfr, null);
```
*Note: For each level of nested rules expected, a ThenInclude query appended will be needed as shown above.*
## How it works
![](https://github.com/microsoft/RulesEngine/blob/main/assets/BlockDiagram.png)

View File

@ -17,45 +17,51 @@ namespace DemoApp
public void Run()
{
Console.WriteLine($"Running {nameof(BasicDemo)}....");
var basicInfo = "{\"name\": \"hello\",\"email\": \"abcy@xyz.com\",\"creditHistory\": \"good\",\"country\": \"canada\",\"loyalityFactor\": 3,\"totalPurchasesToDate\": 10000}";
var orderInfo = "{\"totalOrders\": 5,\"recurringItems\": 2}";
var telemetryInfo = "{\"noOfVisitsPerMonth\": 10,\"percentageOfBuyingToVisit\": 15}";
List<WorkflowRules> workFlowRules = new List<WorkflowRules>();
WorkflowRules workflowRule = new WorkflowRules();
workflowRule.WorkflowName = "Test Workflow Rule 1";
var converter = new ExpandoObjectConverter();
List<Rule> rules = new List<Rule>();
dynamic input1 = JsonConvert.DeserializeObject<ExpandoObject>(basicInfo, converter);
dynamic input2 = JsonConvert.DeserializeObject<ExpandoObject>(orderInfo, converter);
dynamic input3 = JsonConvert.DeserializeObject<ExpandoObject>(telemetryInfo, converter);
Rule rule = new Rule();
rule.RuleName = "Test Rule";
rule.SuccessEvent = "Count is within tolerance.";
rule.ErrorMessage = "Over expected.";
rule.Expression = "count < 3";
rule.RuleExpressionType = RuleExpressionType.LambdaExpression;
rules.Add(rule);
workflowRule.Rules = rules;
workFlowRules.Add(workflowRule);
var bre = new RulesEngine.RulesEngine(workFlowRules.ToArray(), null);
dynamic datas = new ExpandoObject();
datas.count = 1;
var inputs = new dynamic[]
{
input1,
input2,
input3
};
{
datas
};
var files = Directory.GetFiles(Directory.GetCurrentDirectory(), "Discount.json", SearchOption.AllDirectories);
if (files == null || files.Length == 0)
throw new Exception("Rules not found.");
List<RuleResultTree> resultList = bre.ExecuteAllRulesAsync("Test Workflow Rule 1", inputs).Result;
var fileData = File.ReadAllText(files[0]);
var workflowRules = JsonConvert.DeserializeObject<List<WorkflowRules>>(fileData);
bool outcome = false;
var bre = new RulesEngine.RulesEngine(workflowRules.ToArray(), null);
string discountOffered = "No discount offered.";
List<RuleResultTree> resultList = bre.ExecuteAllRulesAsync("Discount", inputs).Result;
//Different ways to show test results:
outcome = resultList.TrueForAll(r => r.IsSuccess);
resultList.OnSuccess((eventName) => {
discountOffered = $"Discount offered is {eventName} % over MRP.";
Console.WriteLine($"Result '{eventName}' is as expected.");
outcome = true;
});
resultList.OnFail(() => {
discountOffered = "The user is not eligible for any discount.";
outcome = false;
});
Console.WriteLine(discountOffered);
Console.WriteLine($"Test outcome: {outcome}.");
}
}
}

61
demo/DemoApp/JSONDemo.cs Normal file
View File

@ -0,0 +1,61 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using RulesEngine.Models;
using System;
using System.Collections.Generic;
using System.Dynamic;
using System.IO;
using static RulesEngine.Extensions.ListofRuleResultTreeExtension;
namespace DemoApp
{
public class JSONDemo
{
public void Run()
{
Console.WriteLine($"Running {nameof(JSONDemo)}....");
var basicInfo = "{\"name\": \"hello\",\"email\": \"abcy@xyz.com\",\"creditHistory\": \"good\",\"country\": \"canada\",\"loyalityFactor\": 3,\"totalPurchasesToDate\": 10000}";
var orderInfo = "{\"totalOrders\": 5,\"recurringItems\": 2}";
var telemetryInfo = "{\"noOfVisitsPerMonth\": 10,\"percentageOfBuyingToVisit\": 15}";
var converter = new ExpandoObjectConverter();
dynamic input1 = JsonConvert.DeserializeObject<ExpandoObject>(basicInfo, converter);
dynamic input2 = JsonConvert.DeserializeObject<ExpandoObject>(orderInfo, converter);
dynamic input3 = JsonConvert.DeserializeObject<ExpandoObject>(telemetryInfo, converter);
var inputs = new dynamic[]
{
input1,
input2,
input3
};
var files = Directory.GetFiles(Directory.GetCurrentDirectory(), "Discount.json", SearchOption.AllDirectories);
if (files == null || files.Length == 0)
throw new Exception("Rules not found.");
var fileData = File.ReadAllText(files[0]);
var workflowRules = JsonConvert.DeserializeObject<List<WorkflowRules>>(fileData);
var bre = new RulesEngine.RulesEngine(workflowRules.ToArray(), null);
string discountOffered = "No discount offered.";
List<RuleResultTree> resultList = bre.ExecuteAllRulesAsync("Discount", inputs).Result;
resultList.OnSuccess((eventName) => {
discountOffered = $"Discount offered is {eventName} % over MRP.";
});
resultList.OnFail(() => {
discountOffered = "The user is not eligible for any discount.";
});
Console.WriteLine(discountOffered);
}
}
}

View File

@ -8,6 +8,7 @@ namespace DemoApp
public static void Main(string[] args)
{
new BasicDemo().Run();
new JSONDemo().Run();
new NestedInputDemo().Run();
new EFDemo().Run();
}