抽取非基本驗證到規則文件 - A2D規則引擎


基本驗證業務驗證,基本驗證就是始終保持不變的驗證規則,可以通過如下硬編碼實現:

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來負責)。所以要用規則文件來分開規則的編寫,好處:

  1. 把修改的職責交給別人,比如項目經理、項目實施人員
  2. 代碼不需要重新編譯就能實現業務規則的修改

我們來解決下這個易變問題,假設有2公司:A和B。

A公司驗證規則:

  1. 基本驗證(就是Order類的驗證規則的硬編碼)
  2. 自定義驗證規則:當前Order的下單網址必須來自於這幾個url,如:www.cnblogs.com、www.cnblogs1.com、www.cnblogs2.com

B公司驗證規則:

  1. 基本驗證(同上) 
  2. 自定義驗證規則:無

如果用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. 可以不寫,但是最多只能存在1個這樣的section
  2. 每行可以有逗號,也可以沒有逗號
  3. 這個section的本意是:當前規則文件的變量全局定義、初始化工作
  4. 開頭為declare,小寫
  5. 結尾為end declare,小寫

rule section:

  1. 必須存在1到多個
  2. 每行可以有逗號,也可以沒有逗號
  3. 開頭為rule "一些描述",小寫
  4. 結尾為end rule,小寫
  5. 如果存在3個rule時,最終會變成這樣的js邏輯
  6. 加載underscore的js代碼
    
    加載declare section的js代碼
    
    if(rule1 conditions)
    {
          執行rule1的then語句
    }
    else if(rule2 conditions)
    {
          執行rule2的then語句
    }
    else if(rule3 conditions)
    {
          執行rule3的then語句
    }

     

大家可以下載代碼進行自己修改,比如可以插入自己編寫的js代碼來更加簡化或者更加貼近項目的自定義方法、函數。

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM