使用 RulesEngine 自定义规则匹配

在之前的例子中规则,不管是触发事件还是支付,规则相对都是比较简单且匹配都总是成功的,但现实中的规则可能会比较复杂并且也有获取积分可能失败的规则。比如将合作伙伴的积分转移到当前平台,我们需要检验合作伙伴是否合法,如果非法时应阻止积分转移的发生。

创建自定义规则

在之前的例子中的 Expression 中,只能使用系统自带的,即 System 库中提供的方法进行逻辑判断。比如 string 自带的方法、int 自带的方法。若想使用自定义方法,则需要进行额外的处理。首先需要一个静态类中的静态方法。

public static class PartnerUtil
{
    private static readonly List<string> ValidPartnerNames = new()
    {
        "AS", "DF", "GH"
    };

    public static bool ValidatePartner(string partnerName) => ValidPartnerNames.Contains(partnerName);
}
复制代码

这里有一些需要注意的地方

  1. 我们定义了一个静态类来处理合作伙伴的相关方法并提供了合作伙伴校验的静态方法。
  2. 这里只是简单的进行名称合法性校验,我们假设我们支持的合作伙伴只有三个,其余的均为非法。
  3. 即使只是名称校验,这些名称不应该硬编码在代码中,而是由运营人员配置,在运行时获取,这里只是作为一个示例。
  4. 对外提供的静态方法返回值不一定是 bool,返回值还可以在 Expression 中继续进行运算最终得出一个 bool 值,这里依然只是一个很简单的例子。
  5. 这里的静态方法甚至可以是一个扩展方法。

注册自定义规则

在我们初始化 RulesEngine 的时候我们需要注册之前的自定义规则,这样才能在规则引擎中使用该规则。

var reSettings = new ReSettings()
{
    CustomTypes = new[] {typeof(PartnerUtil)}
};
_engine = new RulesEngine.RulesEngine(workflowRules, null, reSettings);
复制代码

我们之前的 RulesEngine 初始化时只传入了 workflowRules,这里需要改用重载的另一个构造器传入我们自定义的 reSettings。题外话,第二个没有传的参数是 logger,我们的例子里没有 logger。

使用自定义规则

然后我们就可以在规则中使用我们之前定义的规则了,下面是新定义的一个 Workflow

{
    "WorkflowName": "Transformation",
    "Rules": [
        {
            "RuleName": "TransForMore",
            "SuccessEvent": "Transfer points succeed",
            "RuleExpressionType": "LambdaExpression",
            "Expression": "PartnerUtil.ValidatePartner(partnerName)",
            "ErrorMessage": "Transfer points failed, invalid partner name",
            "ErrorType": "Error",
        }
    ]
}
复制代码

该规则和之前的其他规则有以下不同

  1. Expression 使用了自定义规则。
  2. 引入了 ErrorType 和 ErrorMessage 来确定规则匹配失败之后的处理。
    1. ErrorType 可以是 Warning 和 Error,
    2. 而 ErrorMessage 与 SuccessEvent 对应,应该是失败之后传出的消息,但失败之后的函数不接收参数,所以我确实没有找到这个 ErrorMessage 被用到的地方。

另外,这里使用的是 SuccessEvent 而不是 Actions.OnSuccess 仅仅是因为偷懒。

然后,不要忘了使用规则是注入参数

input.Add(new RuleParameter("partnerName", args.GetProperty("partnerName").GetString()));
复制代码

最后我们还需要定订阅我们的规则触发失败的事件

resultList.OnFail(() =>
{
    response = new RuleResponse() {Message = "Trigger rule failed"};
});
复制代码

我们可以看到该事件不像 OnSuccess 事件有一个参数,接收 SuccessEvent,所以规则中的 ErrorMessage 就丢失了。以下是 OnFail 的源代码。

public static List<RuleResultTree> OnFail(
    this List<RuleResultTree> ruleResultTrees,
    ListofRuleResultTreeExtension.OnFailureFunc onFailureFunc)
{
    if (ruleResultTrees.All<RuleResultTree>((Func<RuleResultTree, bool>) (ruleResult => !ruleResult.IsSuccess)))
    onFailureFunc();
    return ruleResultTrees;
}

public delegate void OnFailureFunc();
复制代码

调用调试

跑起来

合法的合作伙伴,转移成功

image.png

非法的合作伙伴,转移失败

image.png

分类:
后端
标签: