上一篇文章简介了积分系统和它的核心规则引擎,这里我们尝试利用开源规则引擎实现上一篇中提到的一个常用积分获取事件。
我们这里使用的规则引擎是微软开源的 .net 平台的 RulesEngine。它使用 JSON 格式,通过 lambda 表达式描述规则。
引入依赖
在项目中使用 NuGet 管理器搜索 RulesEngine 进行安装,也可以使用 NuGet Package Manager 或者 dotnet 等 command line 工具进行安装,具体命令可以在 NuGet 网站查到
用 JSON 格式写入规则数据
以下是一个最简单的规则,以注册获取积分为例:
[
{
"WorkflowName": "Register",
"Rules": [
{
"RuleName": "Give100Points",
"SuccessEvent": "100",
"RuleExpressionType": "LambdaExpression",
"Expression": "true"
}
]
}
]
复制代码
以下是它的参数说明,需要注意的是 C# 默认使用 big camel 命名法,和 JSON 中常见的 camel 命名法有一点不同。
参数名 | 类型 | 说明 |
---|---|---|
-- | array | 顶层元素,单个元素类型为 WorkflowRules |
WorkflowRules
参数说明
参数名 | 类型 | 说明 |
---|---|---|
WorkflowName | string | execute 的时候根据该参数确定被执行的规则 |
Rules | array | 校验用的规则,单个元素为一个规则,规则之间可以由 And, AndAlso, Or,OrElse 连接,单个元素类型为 Rule |
Rule
参数说明
参数名 | 类型 | 说明 |
---|---|---|
RuleName | string | 规则名称 |
SuccessEvent | string | 在 onSuccess 事件中作为参数被传入 |
RuleExpressionType | string | 现在只能为 "LambdaExpression" |
Expression | string | 根据输入参数进行规则判断的 lambda 表达式,在注册流程中没有参数被传入,直接返回 true 即可 |
使用规则
public class RuleService
{
private readonly RulesEngine.RulesEngine _engine;
public RuleService()
{
const string data = @"
[
{
""WorkflowName"": ""Register"",
""Rules"": [
{
""RuleName"": ""Give100Points"",
""SuccessEvent"": ""100"",
""RuleExpressionType"": ""LambdaExpression"",
""Expression"": ""true""
}
]
}
]";
var workflowRules = JsonConvert.DeserializeObject<WorkflowRules[]>(data);
_engine = new RulesEngine.RulesEngine(workflowRules);
}
public async Task<string> Verify()
{
string discountOffered = null;
var resultList = await _engine.ExecuteAllRulesAsync("Register", Array.Empty<object>());
resultList.OnSuccess(it => discountOffered = $"Register success and get {it} points");
return discountOffered;
}
}
复制代码
代码说明
- 在构造函数中将我们的 JSON 转变成 WorkflowRules 类型的数组再利用它初始化一个 RulesEngine 类型的 _engine。后期优化可以将这个 _engine 由外部实现后由 IOC 注入。
- 在使用时调用 _engine 的 ExecuteAllRulesAsync 方法,传入的第一个参数需要为 JSON 中的 WorkflowName 一致,第二个参数是传入进行校验的参数,在注册时没有参数传入,所以这里写一个空数组。需要注意的是该方法是一个异步方法,我们这里使用 await 关键字触发它。
- 注册 OnSuccess 函数在判断成功时获取返回值,其中它接收的参数时 JSON 中的 SuccessEvent。
- 因为注册事件没有失败一说,所以没有注册 OnFail 方法。
- 最后将得到的结果返回,并在 Controller 中封装成一个网络请求。
调用示例
至此,一个最简的规则就实现了。