规则引擎由推理引擎发展而来,是一种嵌入在应用程序中的组件,实现了将业务决策从应用程序代码中分离出来,并使用预定义的语义模块编写业务决策。接受数据输入,解释业务规则,并根据业务规则做出业务决策。比较常见的业务规则引擎有Drools、VisualRules 和iLog。这里介绍另外一个C#开源工具RulesEngine。下面通过一个例子来他如何使用。
1 项目结构
在RulesEngine源代码中添加一个RulesEngineDemo的窗体应用程序,然后引用需要的类库,如下图所示:
2 订单等实体类定义
这里用订单的场景来用规则引擎处理折扣的业务逻辑:
public class Order { public double amount; public double num; public double discount; public double afteramount; public DateTime datetime; public List<items> ItemLists; public string maker;//购买人 public string wfprocess;//审批人 public string wfprocessname;//审批人 public string memo;//备注 public override string ToString() { string res = string.Format("折扣={0},金额={1},审批人={2}({4}),折后金额={3}", discount, amount, wfprocess, afteramount,wfprocessname); return res; } } //用户 public class Emp { public string id; public string leader; public string name; } //明细 public class items { public string productid; public string productname; public double price; public double num; public double discount; public double amount; public double afteramount; }
3 窗体定义
下面我们创建一个订单明细的窗体,用来修改金额等数据,用来测试业务规则是否正常运行:、
1 public partial class FrmOrder : Form 2 { 3 public FrmOrder() 4 { 5 InitializeComponent(); 6 dgvOrder = this.dataGridView1; 7 } 8 9 public DataGridView dgvOrder; 10 private void FrmOrder_Load(object sender, EventArgs e) 11 { 12 this.dataGridView1.Rows.Add(new object[] { "1", "p1", "20", "10", "200", "1","200","01.01" }); 13 this.dataGridView1.Rows.Add(new object[] { "2", "p2", "1", "8", "8", "1", "8", "01.01" }); 14 15 } 16 17 private void 保存SToolStripButton_Click(object sender, EventArgs e) 18 { 19 this.Hide(); 20 } 21 }
然后我们定义一个主界面来定义规则和调用处理逻辑:
1 using RulesEngine; 2 using RulesEngine.BooEvaluator; 3 public partial class Form1 : Form 4 { 5 6 DataGridView dgvOrder = null; 7 public Form1() 8 { 9 InitializeComponent(); 10 } 11 12 private void Form1_Load(object sender, EventArgs e) 13 { 14 this.dataGridView1.Rows.Add(new object[] {"return (订单.金额>200)",@" 15 订单.折扣=0.9; 16 订单.审批人=""admin""; 17 订单.折后金额=订单.金额*订单.折扣; 18 订单.备注 = ""规则引擎产生""; 19 return true;" }); 20 this.dataGridView1.Rows.Add(new object[] {"return (订单.金额<=200 且 订单.金额>100)",@" 21 订单.折扣=0.8; 22 订单.折后金额=订单.金额*订单.折扣; 23 订单.备注 = ""规则引擎产生""; 24 return true;" }); 25 26 this.dataGridView1.Rows.Add(new object[] {"return (订单.金额<=100 且 订单.金额>0)",@" 27 订单.折扣=1.0; 28 订单.折后金额=订单.金额*订单.折扣; 29 订单.备注 = ""规则引擎产生""; 30 return true;" }); 31 32 } 33 //run 34 private void 保存SToolStripButton_Click(object sender, EventArgs e) 35 { 36 37 38 DslRuleTests test = new DslRuleTests(); 39 test.Setup(); 40 41 //test.EvaluateRules(); 42 43 var order = test.EvaluateRules(this.dataGridView1, dgvOrder); 44 this.txtResults.Text = order.ToString(); 45 46 47 48 } 49 50 private void toolStripButton1_Click(object sender, EventArgs e) 51 { 52 FrmOrder frm = new FrmOrder(); 53 54 frm.ShowDialog(); 55 56 dgvOrder = frm.dgvOrder; 57 } 58 } 59 60 public class DslRuleTests 61 { 62 private BooLangEvaluator evaluator; 63 64 private List<Emp> listEmp = new List<Emp>(); 65 66 public void Setup() 67 { 68 var dslEngineStorage = new DslEngineStorage(); 69 70 evaluator = new BooLangEvaluator(dslEngineStorage); 71 72 listEmp.Add(new Emp { id = "01", leader ="00" ,name="jack"}); 73 listEmp.Add(new Emp { id = "01.01", leader = "01", name = "smith" }); 74 listEmp.Add(new Emp { id = "01.01.01", leader = "01.01", name = "john" }); 75 76 77 } 78 //审批处理 79 private void SP(Order o) 80 { 81 82 foreach (Emp emp in listEmp) 83 { 84 if (emp.id == o.maker) 85 { 86 o.wfprocess = emp.leader; 87 o.wfprocessname = getName(o.wfprocess); 88 } 89 } 90 91 92 } 93 //获取职工姓名 94 private string getName(string id) 95 { 96 foreach (Emp emp in listEmp) 97 { 98 if (emp.id == id) 99 { 100 101 return emp.name; 102 } 103 } 104 return ""; 105 } 106 //求和 107 private void SumAmount(Order o) 108 { 109 var sum = o.ItemLists.AsQueryable().Sum(x => x.amount); 110 o.amount = sum; 111 } 112 //解析规则脚本 113 public Order EvaluateRules(DataGridView dgv,DataGridView dgvOrder) 114 { 115 Order order =new Order { memo = "", maker = "01.01", discount = 1, datetime = DateTime.Now }; 116 order.ItemLists = new List<items>(); 117 foreach (DataGridViewRow dr in dgvOrder.Rows) 118 { 119 if (dr.Cells[0].Value != null) 120 { 121 var item = new items 122 { 123 productid = dr.Cells[0].Value.ToString(), 124 productname = dr.Cells[1].Value.ToString(), 125 price = double.Parse(dr.Cells[2].Value.ToString()), 126 num = double.Parse(dr.Cells[3].Value.ToString()), 127 amount = double.Parse(dr.Cells[4].Value.ToString()), 128 discount = double.Parse(dr.Cells[5].Value.ToString()), 129 afteramount = double.Parse(dr.Cells[6].Value.ToString()) 130 131 }; 132 133 order.ItemLists.Add(item); 134 } 135 } 136 137 SumAmount(order); 138 SP(order); 139 string strDslStatement=""; 140 string strDslActivity = ""; 141 EvaluatorAccessPoint.DslConditionEvaluator = evaluator; 142 143 foreach (DataGridViewRow dr in dgv.Rows) 144 { 145 146 strDslStatement = dr.Cells[0].Value.ToString() 147 .Replace("订单", "this") 148 .Replace("金额", "amount") 149 .Replace("且", "and") 150 .Replace("或", "or"); 151 strDslActivity = dr.Cells[1].Value.ToString() 152 .Replace("折扣", "discount") 153 .Replace("折后金额", "afteramount") 154 .Replace("金额", "amount") 155 .Replace("订单", "this") 156 .Replace("备注", "memo") 157 .Replace("审批人", "wfprocessname") 158 .Replace("且", "and") 159 .Replace("或", "or"); 160 161 var conditionRule = new DslCondition { DslStatement = strDslStatement }; 162 163 var rule = new ActivityRule(conditionRule, new DslActivity 164 { 165 DslStatement = strDslActivity 166 }); 167 168 var result = rule.Evaluate(order); 169 if (result) 170 { 171 //break; 172 return order; 173 174 } 175 176 177 } 178 return null; 179 180 } 181 182 }
4 结果展示
运行代码,界面如下: