程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> 抽取非基本驗證到規則文件:A2D規則引擎

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

編輯:關於.NET

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

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代碼來更加簡化或者更加貼近項目的自定義方法、函數。

查看本欄目

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved