.NET的RulesEngine(规则引擎)使用

2023-11-20

1、背景说明

1.1 规则引擎的使用场景

RulesEngine是Microsoft推出的一个规则引擎项目,用于系统中抽象出的业务逻辑/规则/策略。在医疗行业中经常涉及的功能就是知识库或CDSS,这个基本上就是各种各样的规则集合及提示。例如:两个药品之间会有配伍禁忌、相互作用,因此不能一起配液或同时使用;某药品的给药频率为一天一次(QD),不可为一天三次(TID)、一天四次(QID)等。而这种场合的特点就是输入信息基本不变,规则经常变(常常是增加)。现阶段增加意味着增加代码,发布版本。因此普通企业/软件的这种需求,特别适合规则引擎。
偶然在网上看到规则引擎,当天就研究了下,真的是太好用了!所以总结一下

1.2 demo的代码说明

我用的环境:win10企业版、VS2019社区版,.NET Framework 4.7.2,然后新建控制台程序

2、演示

首先从NuGet上下载并安装RulesEngine。如图所示
在这里插入图片描述

2.1 入门demo演示

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
using RulesEngine.Models;


namespace REDemo2
{
    class Program
    {
        static async Task Main(string[] args)
        {
            //模拟用户的输入内容
            var userInput = new UserInput
            {
                IdNo = null,
                Age = 18
            };


            //定义规则
            var rulesStr = @"[{
                    ""WorkflowName"": ""UserInputWorkflow"",
                    ""Rules"": [
                      {
                        ""RuleName"": ""CheckAge"",
                        ""ErrorMessage"": ""年龄必须大于18岁."",
                        ""ErrorType"": ""Error"",
                        ""RuleExpressionType"": ""LambdaExpression"",
                        ""Expression"": ""Age > 18""
                      },
                       {
                        ""RuleName"": ""CheckIDNoIsEmpty"",
                        ""ErrorMessage"": ""身份证号不可以为空."",
                         ""ErrorType"": ""Error"",
                        ""RuleExpressionType"": ""LambdaExpression"",
                        ""Expression"": ""IdNo != null""
                      }
                    ]
                  }] ";

            //反序列化Json格式规则字符串
            var workflowRules = JsonConvert.DeserializeObject<List<WorkflowRules>>(rulesStr);

            //初始化规则引擎
            var rulesEngine = new RulesEngine.RulesEngine(workflowRules.ToArray());

            //使用规则进行判断,并返回结果
            List<RuleResultTree> resultList = await rulesEngine.ExecuteAllRulesAsync("UserInputWorkflow", userInput);

            //返回结果并展示
            foreach (var item in resultList)
            {
                Console.WriteLine("验证成功:{0},消息:{1}", item.IsSuccess, item.ExceptionMessage);
            }

            Console.ReadLine();
        }
    }

    public class UserInput
    {
        public string IdNo { get; set; }
        public int Age { get; set; }
    }

}


代码的规则,只是简单的验证年龄必须大于18岁及身份证号不能为空。
运行以上代码,展示的结果如下:
在这里插入图片描述
可以通过以上的入门demo展示规则引擎的使用。

2.1.2 代码下载

样例代码下载。代码下载 提取码:NHZL

2.2 规则参数说明

先拿一个完整的样例说一下规则,如下图所示
在这里插入图片描述
整个规则分为如上图的三部分,这三者又是嵌套的关系。其中1和3是必须的,2可有可无。若没有2,则全部按默认处理。这三部分的定义如下

2.2.1 第一部分参数说明

第一部分的参数只有两个。两个都是必须项,具体定义如下

参数名称 类型 说明 必须
WorkflowName string 定义被规则引擎识别的名称
Rules array 具体的规则。规则可以进行多层嵌套

2.2.2 第二部分参数说明

第二部分官方文档中称之为Rule。具体定义如下

参数名称 类型 说明 必须
RuleName string 规则的名称
Operator enum 操作符.用于第3部分多个规则之间的关系。共有4种:AndAndAlsoOrOrElse
ErrorMessage string 错误信息。用于返回的信息
ErrorType enum 错误类型。共有两种:WarningError
SuccessEvent string 完成事件,默认为规则名称
Rules Rules 规则数组,也就说可以嵌套

2.2.3 第三部分参数说明

第三部分参数在文档中称之为Leaf Rule,意思就是最小的规则。也就是具体规则内容。

参数名称 类型 说明 必须
RuleName string 规则的名称
Expression string 表单式,具体的规则内容
RuleExpressionType enum 虽然是枚举类型,但目前只有一种,只能填写LambdaExpression
ErrorMessage string 提示的错误信息
ErrorType enum 错误类型。共有两种:WarningError
SuccessEvent string 完成事件,默认为规则名称

以上定义的官方文档:官方文档链接

2.3 在Expression使用自定义判断

上面的例子在第三部分的参数(leaf rule)的Expression中,只能使用系统(system)自带的方法进行逻辑判断。即string自带的方法、int自带的方法。若想使用自定义方法,则需要进行额外的处理。

2.3.1 先编写业务逻辑判断方法

首先先编写业务逻辑判断方法,如下所示

    public static class IdCardUtil
    {
        //此处使用了C#的方法扩展
        public static int GetAgeByIdCard(this string str)
        {
            //假设进行了相关处理,得到结果
            return 45;
        }

        //此处是正常的业务逻辑方法
        public static int getAgeByIdCardNo(string str)
        {
            return 50;
        }
    }

2.3.2 通过ReSettings进行增加自定义类型

然后通过ReSettings增加自定义类型

        private static readonly RulesEngine.Models.ReSettings reSettings = new RulesEngine.Models.ReSettings
        {
            CustomTypes = new[] { typeof(IdCardUtil) }
        };

2.3.2 修改具体规则

//定义规则
            var rulesStr = @"[{
                    ""WorkflowName"": ""UserInputWorkflow"",
                    ""Rules"": [
                      {
                        ""RuleName"": ""CheckNestedSimpleProp"",
                        ""ErrorMessage"": ""年龄必须小于18岁."",
                        ""ErrorType"": ""Error"",
                        ""RuleExpressionType"": ""LambdaExpression"",
                        ""Expression"": ""IdCardUtil.getAgeByIdCardNo(IdNo) < 18""   //这是常用的方法。
                        ""Expression"": ""IdNo.GetAgeByIdCard() < 18""    // 这个是使用C#自定义扩展方法。 这两句任选一个就可以。
                      },
                       {
                        ""RuleName"": ""CheckNestedSimpleProp1"",
                        ""ErrorMessage"": ""身份证号不可以为空."",
                         ""ErrorType"": ""Error"",
                        ""RuleExpressionType"": ""LambdaExpression"",
                        ""Expression"": ""IdNo != null""
                      }
                    ]
                  }] ";

规则中""Expression"": ""IdCardUtil.getAgeByIdCardNo(IdNo) < 18""""Expression"": ""IdNo.GetAgeByIdCard() < 18""的效果是一样的,任选一个就OK了

2.3.3 将自定义类型进行注册

将自定义的内容进行注册

var rulesEngine = new RulesEngine.RulesEngine(workflowRules.ToArray(),null,reSettings); //添加reSettings内容

然后就可以正常运行了。

2.3.4 代码下载

源码下载。代码 提取码:NHZL

2.4 其他参数说明

2.4.1 RuleParameter(规则参数)

可以对输入内容可以使用RuleParameter来进行封装具体的参数类型。

//这是原始的输入
var zhenglininfo = new UserInput
{
    IdNo = null,
    Age = 18
};
//使用RuleParameter进行封装			
RulesEngine.Models.RuleParameter ruleParameter = new RulesEngine.Models.RuleParameter("Test", zhenglininfo);
.....
//相应的修改
List<RulesEngine.Models.RuleResultTree> resultList = await rulesEngine.ExecuteAllRulesAsync("UserInputWorkflow", ruleParameter);

2.4.2 LocalParams(本地变量)

这个比较重要,这个会将多个条件进行拆分,并分别单独命名,然后使用这些命名进行逻辑判断。例如

            var rulesStr = @"[{
                    ""WorkflowName"": ""UserInputWorkflow"",
                    ""Rules"": [
                                    {
                                        ""RuleName"": ""CheckAge"",
                                        ""ErrorMessage"": ""年龄必须大于18岁."",
                                        ""ErrorType"": ""Error"",
                                        ""localParams"": [
                                          {
                                                ""Name"": ""model1"",
                                                ""Expression"": ""Age!=0""
                                          },
                                          {
                                                ""Name"": ""model2"",
                                                ""Expression"": ""IdCardUtil.getAgeByIdCardNo(Test.IdNo) < 18""
                                          }
                                        ],
                                        ""RuleExpressionType"": ""LambdaExpression"",
                                        ""Expression"": ""model1 AND model2""
                                    },
                                    {
                                        ""RuleName"": ""CheckIDNoIsEmpty"",
                                        ""ErrorMessage"": ""身份证号不可以为空."",
                                         ""ErrorType"": ""Error"",
                                        ""RuleExpressionType"": ""LambdaExpression"",
                                        ""Expression"": ""IdNo != null ""
                                    }
                                ]
                            }] ";

上面就是本地变量的规则样例,其中model2中,传入了Test.IdNo,这就是用到了2.4.1的RuleParameter。

2.4.2.1 代码下载

LocalParams的代码下载。下载地址 提取码:NHZL

2.4.3 GlobalParams(全局变量)

GlobalParams(全局变量)是定义在workflow层面,并且可以在任何rule中使用。例如:

//Rule.json
{
  "WorkflowName": "workflowWithGlobalParam",
  "GlobalParams":[
    {
      "Name":"myglobal1",
      "Expression":"myInput.hello.ToLower()"
    }
  ],
  "Rules":[
    {
      "RuleName": "checkGlobalEqualsHello",
      "Expression":"myglobal1 == \"hello\""
    },
    {
      "RuleName": "checkGlobalEqualsInputHello",
      "Expression":"myInput.hello.ToLower() == myglobal1"
    }
  ]
}


全局变量会在所有的rule中使用,下面的语句将返回true

//使用规则进行判断,并返回结果
var resultList = await rulesEngine.ExecuteAllRulesAsync("UserInputWorkflow", ruleParameter);

foreach (var item in resultList)
{
    Console.WriteLine("验证成功:{0},消息:{1}", item.IsSuccess, item.ExceptionMessage);
}

2.4.3.2 方法2
var resultList = rulesEngine.ExecuteAllRulesAsync("UserInputWorkflow", ruleParameter).Result;

            resultList.OnSuccess((eventName) => {
                Console.WriteLine("{0}是ok!", eventName);
            }).OnFail(() => {
                Console.WriteLine("失败了!");
            });

两个方法略有不同

2.5 后续学习

规则引擎主要是System.Linq.Dynamic.Core,下一步继续学习下这块内容

2.6 参考资料

主要参考资料有:
1、官网资料。官网
2、波多尔斯基 的《C#规则引擎RulesEngine》
3、微软MVP精选 | .NET RulesEngine(规则引擎)

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

.NET的RulesEngine(规则引擎)使用 的相关文章

  • 每次调用新方法时触发事件

    我正在做一个logger for a c 应用程序需要记录每个方法被调用的时间以及每个方法执行时间 我可以通过调用自己的方法来做到这一点EventLogger LogMethodCall方法在每个方法的开头 但我想知道是否有办法使CLR每次
  • 宏可以按参数数量重载吗?

    如何this https stackoverflow com q 9183993 153285工作 如何实现 C99 C 11 可变参数宏以仅根据为其提供多少个参数来扩展到不同的事物 编辑 请参阅末尾以获得现成的解决方案 要获得重载的宏 首
  • 有没有办法将 boost::json::serializer 切换为美化输出?

    Using boost json serializer如中的示例所示文档 快速查看 http vinniefalco github io doc json json usage quick look html以紧凑格式保存 json tre
  • 使用 size_t 值反向遍历向量

    我想以相反的方向遍历向量的值 如您所知 向量的大小为 size t 当我使用以下代码时 for size t r m size 1 r gt 0 r x r f r for size t c r 1 c lt m size c x r m
  • C++:初始化静态字符串成员

    我在 C 中初始化静态字符串成员时遇到一些问题 我有几个类 每个类都包含几个表示 id 的静态字符串成员 当我通过调用静态函数初始化变量时 一切都很好 但是 当我想为一个变量分配另一个变量的值时 它仍然保留空字符串 这段代码有什么问题 st
  • 本地主机上的 .net HTTP_X_FORWARDED_FOR NULL

    抱歉 如果其他地方已经回答了这个问题 我找不到它 如果没有 我会尝试查找访问过该站点的机器的原始 IP 根据我的基本理解 变量HTTP X FORWARDED FOR无论代理和其他过滤器如何 都会显示用户的 IP 如果这是真的 我正在尝试对
  • 捕获另一个进程未处理的异常

    我想知道我是否可以捕获我开始使用 Process Start 的另一个进程抛出的未处理的异常 我知道我可以用这个捕获标准错误link http social msdn microsoft com Forums en US csharpgen
  • 如何强制用户仅使用“new”创建从我派生的类的对象?

    为了实现引用计数 我们使用IUnknown http msdn microsoft com en us library ms680509 VS 85 aspx类接口和智能指针模板类 该接口具有所有引用计数方法的实现 包括Release vo
  • ASP.NET MVC 路由 - 向路由添加 .html 扩展名

    我对 MVC 和路由非常陌生 我被要求修改一个应用程序以使用不同的 url 由于我没有经验 这项任务对我来说有点困难 好吧 让我们谈谈一些代码 routes MapRoute CategoryBySeName Route name prod
  • 使用 INotifyPropertyChanged

    有人可以解释一下为什么在 wpf 中使用绑定时需要使用 INotifyPropertyChanged 的 实现吗 我可以在不实现此接口的情况下绑定属性吗 例如我有代码 public class StudentData INotifyProp
  • Visual Studio Code 调试默认 ASP.NET Core MVC WebApp:不起作用

    我正在使用 Manjaro linux 并尝试调试默认的 ASP NET Core MVC 项目 但调试停止 没有任何错误 我创建了该项目 dotnet new mvc in a Meow文件夹 没什么特别的 然后添加了新的配置 NET C
  • 将一个整数从 C 客户端发送到 Java 服务器

    我使用此代码将一个整数从我的 Java 客户端发送到我的 Java 服务器 int n rand nextInt 50 1 DataOutputStream dos new DataOutputStream socket getOutput
  • EWS - 给予预约,获取预约的所有者副本

    在 EWS 中进行预约后 是否可以获得所有者的副本 例如 如果我登录为user1 我有user1创建的约会的副本user2 我有冒充权 我要编辑user2预约的副本 我怎样才能获得user2 s copy 您可以使用 PidLidClean
  • char* argv[] 在 c/c++ 中如何工作? [复制]

    这个问题在这里已经有答案了 我知道它用于使用命令行中的参数 但我没有得到声明 字符 argv 它是否意味着指向 char 数组的指针 如果是的话为什么没有大小 如果不是动态数组 就不需要有大小吗 我做了一些研究 发现有人说它会衰减为 cha
  • 未找到 _sqlite3_open 等符号错误

    您好 我收到此错误 Undefined symbols sqlite3 open referenced from main in ccRlWVer o sqliite3 close referenced from main in ccRlW
  • 清理堆分配对象的良好实践或约定?

    我正在学习C 我有 C C ObjC 背景 相当高级的语言 在 C 或 ObjC 上 作为函数或方法的结果返回堆分配的对象是很简单的 因为对象的清理是受管理的 按照惯例 会在适当的时候销毁 但我不知道在 C 中应该如何处理这个问题 例如 s
  • 扔掉挥发物安全吗?

    大多数时候 我都是这样做的 class a public a i 100 OK delete int j Compiler happy But is it safe The following code will lead compilat
  • 如何从尖点库矩阵格式获取原始指针

    我需要从尖点库矩阵格式获取原始指针 例如 cusp coo matrix
  • 如何在没有 Visual Studio 的情况下将新文件添加到 .csproj 文件

    如何添加新文件到 csproj从命令提示符 我认为没有任何工具可以响应命令行上的 add project 命令来执行此操作 但我认为您可以幸运地创建一个程序 脚本来直接操作 csproj 文件的 XML 内容 csproj 文件的结构如下所
  • C# amo 获取角色完整

    我正在开发一个 SSAS 项目 其中除其他事项外 我需要获取 C 中表格多维数据集的完整用户列表 目前我让它以这样的方式工作 我可以获得角色 但数据不完整 当我调用 Server Database Roles 为了便于阅读而简化 属性并枚举

随机推荐

  • Linux系统如何看目录属于哪个磁盘分区

    Linux是先有目录 再有磁盘分区 df h 目录 例如 没有挂载磁盘的目录 显示在系统盘 root iZ2ze57v3n0zma46zqiq8nZ sh 1 5 5 df h alidata Filesystem Size Used Av
  • Unity使用spine动画

    Unity使用spine动画 在 Unity 中 常常使用 Spine 来制作一些动画 引擎本身并不能直接播放 Spine 动画 需要额外导入一个 RunTime 插件库才能支持 官网插件导入 当然 也可以到 Spine 官网关于 Unit
  • 机器学习原理(1)集成学习基本方法

    一 什么是集成学习 集成学习 ensemble learning 通过将多个学习器进行组合来完成学习任务 下图显示集成学习的一般结构 取自周志华老师的西瓜书 个体学习器通常由一种现有的学习算法从训练数据产生 例如决策树 C4 5 CART
  • C语言之——自定义数据类型

    目录 前言 什么是自定义数据类型 一 自定义数据类型之 数据类型命名 1 深入应用typedef 二 自定义数据类型之 结构体类型命名 1 深入理解struct结构体 三 自定义数据类型之 联合体类型命名 1 union与struct的区别
  • FreeRTOS多任务调度器基础

    Cortex M4中SysTick调度器核心 Cortex M4中的中断管理 Cortex M4中影子栈指针 Cortex M4中SVC和PendSV异常 1 Cortex M4中SysTick调度器核心 systick每一次中断都会触发内
  • c语言—指针非常全面、详细

    目录 一 初步认识指针 一级 二 数组指针 1 一维数组与指针 2 二维数组与指针 三 函数指针 四 指针数组 2 函数指针数组 五 指针函数 六 二级 多级 指针 七 指针定义的归纳 一 初步认识指针 一级 1 指针变量 指针变量是一个特
  • c++优先队列简介及例题:5.4.1 围栏修复

    优先队列 其实就是个队列 只不过里面的元素会被自动按一定的顺序来排列 可以是递增顺序 也可以是递减顺序 写法如下 头文件 include
  • 020 - STM32学习笔记 - Fatfs文件系统(二) - 移植与测试

    020 STM32学习笔记 Fatfs文件系统 二 移植与测试 上节学习了FatFs文件系统的相关知识 这节内容继续学习在STM32上如何移植FatFs文件系统 并且实现文件的创建 读 写与删除等功能 各位看官觉得还行的话点点赞 收藏一下呗
  • FastDFS-01-单机和集群搭建

    我是码赛客1024 本节我们一起搭建FastDFS 一 介绍 FastDFS是一个开源的轻量级分布式文件系统 它对文件进行管理 功能包括 文件存储 文件同步 文件访问 文件上传 文件下载 等 解决了大容量存储和负载均衡的问题 特别适合以文件
  • 对象创建的几个步骤

    对象创建的几个步骤 一 先把要创建的对象的类信息加载进内存 二 在内存开辟空间 1 如果内存是规整的 则使用指针碰撞 2 如果不规整 则会维护一个空闲列表 内存是否规整根据具体的垃圾回收算法来决定 三 开辟空间需要解决并发问题 在堆中创建对
  • shell脚本一键安装JDK及配置环境变量

    这是我学了半天shell写出来的 不适合大神看 为什么我要写这样安装JDK并配置环境变量的脚本呢 因为我和linux打交道还是比较多的 然而每次都要安装JDK 配置环境变量 这样的事情对于刚接触linux的人来说是很乐意做的 但是接触多了
  • 浏览器请求队列机制-请求为什么会阻塞

    前言 最近遇到一个问题 我1个站点链接2个后端服务 但1个后端服务有问题 导致访问超时 但请求接口都是分开的 自认为一个服务站点请求超时 不会影响到另外一个请求的 但不是 全部请求都发不出去 为什么呢 是不是浏览器有请求机制管理 正常情况前
  • html理解MVC模型与MVVM模型底层实现

    一 MVC模型的底层实现 1 1 相关代码 div div
  • python基础编程小实例13——手机通讯录

    本文更新于2022 05 18 bug已修复 编程语言 python3 9 题目 可以在通讯录中通过姓名查看相关联系人的联系方式等信息 也可以在其中新增联系人 或修改 删除联系人信息 本实例要求编写程序 实现具备添加 查看 修改以及删除联系
  • react 上传文件(多选)功能入的坑

    1 这里报错是因为onChange的this指向不对 解决方法在constructor中写 this onChange this onChange bind this 或者在绑定事件的时候写 onChange this onChange b
  • Unity Animator 动画没切换

    恶魔射手 Survival Shooter 项目 有两个动画 一个是静止时的Idle 一个是走路时候的Move 如下图 设置好动画状态机后发现按方向键后还是Idle 没反应 而一直按着方向键后呢又动起来了 最后找到了真相 原来选中了 Has
  • 使用yolov7模型用VOC深度学习

    yolov7及VOC数据集 权重文件地址 bubbliiiing yolov7 pytorch 这是一个yolov7的库 可以用于训练自己的数据集 github com 在colab中 训练 1 voc annotation py 如果使用
  • Python 判断数组list是否为空

    前言 判断数组为空 是一个常见用法 Python与Java的方法不同 需区分 Python 方法 1 根据长度判断 长度为0时 表示空 其中 判断条件 成立时 非零 则执行后面的语句 lst if len lst print c else
  • 如何在mybatis 中传多个参数,如何在mybatis 中遍历 集合?

    如何在mybatis 中传多个参数 List getIdByRand Param question Question question Param sectionIdList List sectionIdList param 映射参数到 x
  • .NET的RulesEngine(规则引擎)使用

    本文目录 1 背景说明 1 1 规则引擎的使用场景 1 2 demo的代码说明 2 演示 2 1 入门demo演示 2 1 1 代码展示 2 1 2 代码下载 2 2 规则参数说明 2 2 1 第一部分参数说明 2 2 2 第二部分参数说明