抽取非基本验证到规则文件 - A2D规则引擎
2013-09-08 17:35
363 查看
基本验证与业务验证,基本验证就是始终保持不变的验证规则,可以通过如下硬编码实现:
然后在用如下代码validate, 把错误放到List中:
然后说说业务规则的易变
SaaS程序,或者业务规则极其易变时,就要采用其他方法来做了,不可能每个公司都用设计模式分开写(虽然也行,但是不方便,公司业务规则多了后,对这些规则代码的管理就是很高的成本,而且要developer来负责)。所以要用规则文件来分开规则的编写,好处:
把修改的职责交给别人,比如项目经理、项目实施人员
代码不需要重新编译就能实现业务规则的修改
我们来解决下这个易变问题,假设有2公司:A和B。
A公司验证规则:
基本验证(就是Order类的验证规则的硬编码)
自定义验证规则:当前Order的下单网址必须来自于这几个url,如:www.cnblogs.com、www.cnblogs1.com、www.cnblogs2.com
B公司验证规则:
基本验证(同上)
自定义验证规则:无
如果用A2D规则引擎来解决的话,需要怎么做呢?
第一步当然是编写规则文件,A公司的规则文件:
由于B公司没有自定义规则,因此不需要编写相应的规则文件
第二步,调整验证逻辑,如下:
BrokenRule.cs代码:
demo代码已经更新到A2D框架中了,这里就不upload运行图了。
A2D规则引擎已经内嵌了underscore 1.5.2,因此规则定义文件(.r文件)中可以写相应的underscore函数来简化写法。
规则文件说明:
declare section:
可以不写,但是最多只能存在1个这样的section
每行可以有逗号,也可以没有逗号
这个section的本意是:当前规则文件的变量全局定义、初始化工作
开头为declare,小写
结尾为end declare,小写
rule section:
必须存在1到多个
每行可以有逗号,也可以没有逗号
开头为rule "一些描述",小写
结尾为end rule,小写
如果存在3个rule时,最终会变成这样的js逻辑
大家可以下载代码进行自己修改,比如可以插入自己编写的js代码来更加简化或者更加贴近项目的自定义方法、函数。
public class Order { [Required] [Range(typeof(decimal), "1", "10000")] public decimal Price { get; set; } [Required] [StringLength(30)] public string Customer { get; set; } [Required(AllowEmptyStrings=true)] [StringLength(50)] public string StoreID { get; set; } }
然后在用如下代码validate, 把错误放到List中:
private bool ValidateBasicRule(Order order) { List<KeyValuePair<string, string>> errors = order.IsValid(); if (errors.Count > 0) { this.AddRange(errors); return false; } return true; } public static class DataAnnotationHelper { public static List<KeyValuePair<string, string>> IsValid<T>(this T o) { List<KeyValuePair<string, string>> errors = new List<KeyValuePair<string, string>>(); var descriptor = GetTypeDescriptor(typeof(T)); foreach (PropertyDescriptor propertyDescriptor in descriptor.GetProperties()) { foreach (var validationAttribute in propertyDescriptor.Attributes.OfType<ValidationAttribute>()) { if (!validationAttribute.IsValid(propertyDescriptor.GetValue(o))) { errors.Add(new KeyValuePair<string, string>(propertyDescriptor.Name, validationAttribute.FormatErrorMessage(propertyDescriptor.Name))); } } } return errors; } private static ICustomTypeDescriptor GetTypeDescriptor(Type type) { return new AssociatedMetadataTypeTypeDescriptionProvider(type).GetTypeDescriptor(type); } }
然后说说业务规则的易变
SaaS程序,或者业务规则极其易变时,就要采用其他方法来做了,不可能每个公司都用设计模式分开写(虽然也行,但是不方便,公司业务规则多了后,对这些规则代码的管理就是很高的成本,而且要developer来负责)。所以要用规则文件来分开规则的编写,好处:
把修改的职责交给别人,比如项目经理、项目实施人员
代码不需要重新编译就能实现业务规则的修改
我们来解决下这个易变问题,假设有2公司:A和B。
A公司验证规则:
基本验证(就是Order类的验证规则的硬编码)
自定义验证规则:当前Order的下单网址必须来自于这几个url,如:www.cnblogs.com、www.cnblogs1.com、www.cnblogs2.com
B公司验证规则:
基本验证(同上)
自定义验证规则:无
如果用A2D规则引擎来解决的话,需要怎么做呢?
第一步当然是编写规则文件,A公司的规则文件:
declare allowStores=["www.cnblogs.com", "www.cnblogs1.com", "www.cnblogs2.com"] end declare rule "test" when !_.contains(allowStores, entity.StoreID) then errors.Add("StoreID", "StoreID value not right") end rule
由于B公司没有自定义规则,因此不需要编写相应的规则文件
第二步,调整验证逻辑,如下:
public class OrderService : BrokenRulesHolder { public int PlaceOrder(Order order) { this.ClearBrokenRules(); //进行基本规则验证 if (!ValidateBasicRule(order)) return -1; //进行针对不同公司的规则验证 if (!ValidateCompanyRule(order)) return -1; //其他操作,比如插入数据库 return 100; } private bool ValidateCompanyRule(Order order) { BrokenRulesHolder tempBrokenRulesHolder = new BrokenRulesHolder(); string rulePath = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Rules", "OrderValidations", SessionContext.CompanyID + ".r"); using (RuleEngine engine = new RuleEngine(false)) //false代表:如果规则文件不存在不会报错,而是忽略,默认为true { engine.BindRulePath(rulePath); //将规则文件的全路径传入引擎 engine.SetParameter("entity", order); engine.SetParameter("errors", tempBrokenRulesHolder); engine.Process(); } if (tempBrokenRulesHolder.BrokenRules.Count > 0) { this.AddRange(tempBrokenRulesHolder.BrokenRules); return false; } return true; } private bool ValidateBasicRule(Order order) { List<KeyValuePair<string, string>> errors = order.IsValid(); if (errors.Count > 0) { this.AddRange(errors); return false; } return true; } }
BrokenRule.cs代码:
public class BrokenRulesHolder { private List<KeyValuePair<string, string>> brokenRules = new List<KeyValuePair<string, string>>(); public List<KeyValuePair<string, string>> BrokenRules { get { return this.brokenRules.AsReadOnly().ToList(); } } public void Add(string key, string msg) { brokenRules.Add(new KeyValuePair<string, string>(key, msg)); } public void AddRange(List<KeyValuePair<string, string>> rules) { brokenRules.AddRange(rules); } public void ClearBrokenRules() { brokenRules.Clear(); } }
demo代码已经更新到A2D框架中了,这里就不upload运行图了。
A2D规则引擎已经内嵌了underscore 1.5.2,因此规则定义文件(.r文件)中可以写相应的underscore函数来简化写法。
规则文件说明:
declare allowStores1=["www.cnblogs.com", "www.cnblogs1.com", "www.cnblogs2.com"] allowStores2=["www.cnblogs.com", "www.cnblogs1.com", "www.cnblogs2.com"] end declare rule "rule 1" when !allowStores1.contains(entity.StoreID) then errors.Add("StoreID", "StoreID value not right") end rule rule "rule 2" when !allowStores2.contains(entity.StoreID) then errors.Add("StoreID", "StoreID value not right") end rule
declare section:
可以不写,但是最多只能存在1个这样的section
每行可以有逗号,也可以没有逗号
这个section的本意是:当前规则文件的变量全局定义、初始化工作
开头为declare,小写
结尾为end declare,小写
rule section:
必须存在1到多个
每行可以有逗号,也可以没有逗号
开头为rule "一些描述",小写
结尾为end rule,小写
如果存在3个rule时,最终会变成这样的js逻辑
加载underscore的js代码 加载declare section的js代码 if(rule1 conditions) { 执行rule1的then语句 } else if(rule2 conditions) { 执行rule2的then语句 } else if(rule3 conditions) { 执行rule3的then语句 }
大家可以下载代码进行自己修改,比如可以插入自己编写的js代码来更加简化或者更加贴近项目的自定义方法、函数。
相关文章推荐
- 抽取非基本验证到规则文件
- jquery validate的动态加入另一个js文件的验证规则
- 用来验证字符串的规则引擎
- easyui学习笔记14-拓展的基本验证规则
- C头文件编写基本规则
- 幻世(OurDream)2D图形引擎使用教程4——基本图形的绘制
- struts2验证规则validation配置文件命名方式总结
- 基于文件数据库的规则引擎处理海量高复杂度数据(一,业务背景)
- kohana框架上传文件验证规则写法示例
- 幻世(OurDream)2D图形引擎使用教程3——基本图形的绘制
- 基于文件数据库的规则引擎处理海量高复杂度数据(二,解决方案)
- 幻世(OurDream)2D图形引擎使用教程11——播放媒体文件(1)
- 极其好用好学的规则引擎 - A2D规则引擎
- 【小旋风开发日记】异步拉取html源代码、网页编码自动识别、基本xpath的智能抽取引擎的优化
- Windows搜索DLL文件的基本规则
- struts2学习之验证框架四规则文件的书写风格
- Struts2 验证规则配置文件
- struts2验证规则validation配置文件命名方式总结
- struts2验证规则validation配置文件命名方式总结
- django(7)modelform操作及验证、ajax操作普通表单数据提交、文件上传、富文本框基本使用