Merge docs to main (#288)
* added more docs for local params and actions * updated text * fixed typo * added wiki link in doc * added information on expression language * fixed linkspull/289/head
parent
53213bf13e
commit
60b6561f27
259
docs/index.md
259
docs/index.md
|
@ -1,7 +1,7 @@
|
|||
## Description
|
||||
RulesEngine is a highly extensible library to build rule based system using C# expressions
|
||||
|
||||
## Features
|
||||
|
||||
**Features**
|
||||
- Json based rules defination
|
||||
- Multiple input support
|
||||
- Dynamic object input support
|
||||
|
@ -10,6 +10,27 @@ RulesEngine is a highly extensible library to build rule based system using C# e
|
|||
- Scoped parameters
|
||||
- Post rule execution actions
|
||||
|
||||
**Table Of Content**
|
||||
- [Installation](#installation)
|
||||
- [Basic Usage](#basic-usage)
|
||||
- [Create a workflow file with rules](#create-a-workflow-file-with-rules)
|
||||
- [Initialise RulesEngine with the workflow:](#initialise-rulesengine-with-the-workflow)
|
||||
- [Execute the workflow rules with input:](#execute-the-workflow-rules-with-input)
|
||||
- [Using custom names for inputs](#using-custom-names-for-inputs)
|
||||
- [C# Expression support](#c-expression-support)
|
||||
- [ScopedParams](#scopedparams)
|
||||
- [GlobalParams](#globalparams)
|
||||
- [Example](#example)
|
||||
- [LocalParams](#localparams)
|
||||
- [Example](#example-1)
|
||||
- [Referencing ScopedParams in other ScopedParams](#referencing-scopedparams-in-other-scopedparams)
|
||||
- [Post rule execution actions](#post-rule-execution-actions)
|
||||
- [Inbuilt Actions](#inbuilt-actions)
|
||||
- [OutputExpression](#outputexpression)
|
||||
- [Usage](#usage)
|
||||
- [Custom Actions](#custom-actions)
|
||||
- [Steps to use a custom Action](#steps-to-use-a-custom-action)
|
||||
|
||||
|
||||
|
||||
## Installation
|
||||
|
@ -92,6 +113,13 @@ var resultList = await re.ExecuteAllRulesAsync("DiscountWithCustomInputNames",r
|
|||
|
||||
```
|
||||
|
||||
## C# Expression support
|
||||
The lambda expression allows you to use most of C# constructs and along with some of linq features.
|
||||
|
||||
For more details on supported expression language refer - [expression language](https://dynamic-linq.net/expression-language)
|
||||
|
||||
For supported linq operations refer - [sequence operators](https://dynamic-linq.net/expression-language#sequence-operators)
|
||||
|
||||
|
||||
## ScopedParams
|
||||
Sometimes Rules can get very long and complex, scopedParams allow users to replace an expression in rule with an alias making it easier to maintain rule.
|
||||
|
@ -106,7 +134,7 @@ GlobalParams are defined at workflow level and can be used in any rule.
|
|||
|
||||
#### Example
|
||||
|
||||
```json
|
||||
```jsonc
|
||||
//Rule.json
|
||||
{
|
||||
"WorkflowName": "workflowWithGlobalParam",
|
||||
|
@ -141,3 +169,228 @@ These rules when executed with the below input will return success
|
|||
```
|
||||
|
||||
|
||||
### LocalParams
|
||||
LocalParams are defined at rule level and can be used by the rule and its child rules
|
||||
|
||||
#### Example
|
||||
|
||||
```jsonc
|
||||
//Rule.json
|
||||
{
|
||||
"WorkflowName": "workflowWithLocalParam",
|
||||
|
||||
"Rules":[
|
||||
{
|
||||
"RuleName": "checkLocalEqualsHello",
|
||||
"LocalParams":[
|
||||
{
|
||||
"Name":"mylocal1",
|
||||
"Expression":"myInput.hello.ToLower()"
|
||||
}
|
||||
],
|
||||
"Expression":"mylocal1 == \"hello\""
|
||||
},
|
||||
{
|
||||
"RuleName": "checkLocalEqualsInputHelloInNested",
|
||||
"LocalParams":[
|
||||
{
|
||||
"Name":"mylocal1", //redefined here as it is scoped at rule level
|
||||
"Expression":"myInput.hello.ToLower()"
|
||||
}
|
||||
],
|
||||
"Operator": "And",
|
||||
"Rules":[
|
||||
{
|
||||
"RuleName": "nestedRule",
|
||||
"Expression":"myInput.hello.ToLower() == mylocal1" //mylocal1 can be used here since it is nested to Rule where mylocal1 is defined
|
||||
}
|
||||
]
|
||||
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
These rules when executed with the below input will return success
|
||||
```c#
|
||||
var input = new RuleParameter("myInput",new {
|
||||
hello = "HELLO"
|
||||
});
|
||||
|
||||
var resultList = await re.ExecuteAllRulesAsync("workflowWithLocalParam",rp);
|
||||
```
|
||||
|
||||
### Referencing ScopedParams in other ScopedParams
|
||||
|
||||
Similar to how ScopedParams can be used in expressions, they can also be used in other scoped params that come after them.
|
||||
This allows us to create multi-step rule which is easier to read and maintain
|
||||
|
||||
|
||||
```jsonc
|
||||
//Rule.json
|
||||
{
|
||||
"WorkflowName": "workflowWithReferencedRule",
|
||||
"GlobalParams":[
|
||||
{
|
||||
"Name":"myglobal1",
|
||||
"Expression":"myInput.hello"
|
||||
}
|
||||
],
|
||||
"Rules":[
|
||||
{
|
||||
"RuleName": "checkGlobalAndLocalEqualsHello",
|
||||
"LocalParams":[
|
||||
{
|
||||
"Name": "mylocal1",
|
||||
"Expression": "myglobal1.ToLower()"
|
||||
}
|
||||
],
|
||||
"Expression":"mylocal1 == \"hello\""
|
||||
},
|
||||
{
|
||||
"RuleName": "checklocalEqualsInputHello",
|
||||
"LocalParams":[
|
||||
{
|
||||
"Name": "mylocal1",
|
||||
"Expression": "myglobal1.ToLower()"
|
||||
},
|
||||
{
|
||||
"Name": "mylocal2",
|
||||
"Expression": "myInput.hello.ToLower() == mylocal1"
|
||||
}
|
||||
],
|
||||
"Expression":"mylocal2 == true"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
These rules when executed with the below input will return success
|
||||
```c#
|
||||
var input = new RuleParameter("myInput",new {
|
||||
hello = "HELLO"
|
||||
});
|
||||
|
||||
var resultList = await re.ExecuteAllRulesAsync("workflowWithReferencedRule",rp);
|
||||
|
||||
|
||||
```
|
||||
|
||||
## Post rule execution actions
|
||||
As a part of v3, Actions have been introduced to allow custom code execution on rule result. This can be achieved by calling `ExecuteAllRulesAsync` method of RulesEngine
|
||||
|
||||
### Inbuilt Actions
|
||||
RulesEngine provides inbuilt action which cover major scenarios related to rule execution
|
||||
|
||||
#### OutputExpression
|
||||
This action evaluates an expression based on the RuleParameters and returns its value as Output
|
||||
##### Usage
|
||||
Define OnSuccess or OnFailure Action for your Rule:
|
||||
```jsonc
|
||||
{
|
||||
"WorkflowName": "inputWorkflow",
|
||||
"Rules": [
|
||||
{
|
||||
"RuleName": "GiveDiscount10Percent",
|
||||
"SuccessEvent": "10",
|
||||
"ErrorMessage": "One or more adjust rules failed.",
|
||||
"ErrorType": "Error",
|
||||
"RuleExpressionType": "LambdaExpression",
|
||||
"Expression": "input1.couy == \"india\" AND input1.loyalityFactor <= 2 AND input1.totalPurchasesToDate >= 5000 AND input2.totalOrders > 2 AND input2.noOfVisitsPerMonth > 2",
|
||||
"Actions": {
|
||||
"OnSuccess": {
|
||||
"Name": "OutputExpression", //Name of action you want to call
|
||||
"Context": { //This is passed to the action as action context
|
||||
"Expression": "input1.TotalBilled * 0.9"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
Call `ExecuteAllRulesAsync` with the workflowName, ruleName and ruleParameters
|
||||
```c#
|
||||
var ruleResultList = await rulesEngine.ExecuteAllRulesAsync("inputWorkflow",ruleParameters);
|
||||
foreach(var ruleResult in ruleResultList){
|
||||
if(ruleResult.ActionResult != null){
|
||||
Console.WriteLine(ruleResult.ActionResult.Output); //ActionResult.Output contains the evaluated value of the action
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
### Custom Actions
|
||||
RulesEngine allows registering custom actions which can be used in the rules workflow.
|
||||
|
||||
#### Steps to use a custom Action
|
||||
1. Create a class which extends `ActionBase` class and implement the run method
|
||||
```c#
|
||||
public class MyCustomAction: ActionBase
|
||||
{
|
||||
|
||||
public MyCustomAction(SomeInput someInput)
|
||||
{
|
||||
....
|
||||
}
|
||||
|
||||
public override ValueTask<object> Run(ActionContext context, RuleParameter[] ruleParameters)
|
||||
{
|
||||
var customInput = context.GetContext<string>("customContextInput");
|
||||
//Add your custom logic here and return a ValueTask
|
||||
}
|
||||
```
|
||||
Actions can have async code as well
|
||||
```c#
|
||||
public class MyCustomAction: ActionBase
|
||||
{
|
||||
|
||||
public MyCustomAction(SomeInput someInput)
|
||||
{
|
||||
....
|
||||
}
|
||||
|
||||
public override async ValueTask<object> Run(ActionContext context, RuleParameter[] ruleParameters)
|
||||
{
|
||||
var customInput = context.GetContext<string>("customContextInput");
|
||||
//Add your custom logic here
|
||||
return await MyCustomLogicAsync();
|
||||
}
|
||||
```
|
||||
2. Register them in ReSettings and pass it to RulesEngine
|
||||
```c#
|
||||
var reSettings = new ReSettings{
|
||||
CustomActions = new Dictionary<string, Func<ActionBase>>{
|
||||
{"MyCustomAction", () => new MyCustomAction(someInput) }
|
||||
}
|
||||
};
|
||||
|
||||
var re = new RulesEngine(workflowRules,logger,reSettings);
|
||||
```
|
||||
3. You can now use the name you registered in the Rules json in success or failure actions
|
||||
```jsonc
|
||||
{
|
||||
"WorkflowName": "inputWorkflow",
|
||||
"Rules": [
|
||||
{
|
||||
"RuleName": "GiveDiscount10Percent",
|
||||
"SuccessEvent": "10",
|
||||
"ErrorMessage": "One or more adjust rules failed.",
|
||||
"ErrorType": "Error",
|
||||
"RuleExpressionType": "LambdaExpression",
|
||||
"Expression": "input1.couy == \"india\" AND input1.loyalityFactor <= 2 AND input1.totalPurchasesToDate >= 5000 AND input2.totalOrders > 2 AND input2.noOfVisitsPerMonth > 2",
|
||||
"Actions": {
|
||||
"OnSuccess": {
|
||||
"Name": "MyCustomAction", //Name context
|
||||
"Context": { //This is passed to the action as action context
|
||||
"customContextInput": "input1.TotalBilled * 0.9"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
_For more details please check out [Rules Engine Wiki](https://github.com/microsoft/RulesEngine/wiki)._
|
||||
|
|
Loading…
Reference in New Issue