首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> 關於.NET

.NET 規則引擎實戰:A2D 規則引擎將業務驗證外部化至規則檔案

     編輯:關於.NET

前言

資料驗證分為基本驗證 (固定規則:必填、長度、範圍) 與業務驗證 (頻變規則:各客戶不同業務邏輯)。A2D 規則引擎將業務規則外部化為 .r 規則檔案,無需重新編譯即可熱更新,降低維護成本並授權非開發人員維護規則。

基本驗證:Data Annotation 硬編碼


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; }
}

驗證輔助方法


private bool ValidateBasicRule(Order order)
{
    var errors = order.IsValid();
    if (errors.Count > 0) { this.AddRange(errors); return false; }
    return true;
}

public static class DataAnnotationHelper
{
    public static List> IsValid(this T o)
    {
        var errors = new List>();
        var descriptor = GetTypeDescriptor(typeof(T));
        
        foreach (PropertyDescriptor prop in descriptor.GetProperties())
        {
            foreach (var attr in prop.Attributes.OfType())
            {
                if (!attr.IsValid(prop.GetValue(o)))
                {
                    errors.Add(new KeyValuePair(prop.Name, 
                        attr.FormatErrorMessage(prop.Name)));
                }
            }
        }
        return errors;
    }
}

業務規則外部化:A2D 規則檔案

場景:A 公司與 B 公司不同驗證規則

  • 共同基本驗證:Order 類別 Data Annotation
  • A 公司業務規則:StoreID 必須在允許清單中 (www.cnblogs.com 等)
  • B 公司業務規則:無額外規則

A 公司規則檔:A.r

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 公司:無規則檔案

引擎設定 ignoreMissing=true,檔案不存在時自動略過。

驗證邏輯整合


public class OrderService : BrokenRulesHolder
{
    public int PlaceOrder(Order order)
    {
        this.ClearBrokenRules();
        
        // 1. 基本驗證
        if (!ValidateBasicRule(order)) return -1;
        
        // 2. 公司業務規則
        if (!ValidateCompanyRule(order)) return -1;
        
        // 3. 業務邏輯 (如寫入資料庫)
        return 100;
    }

    private bool ValidateCompanyRule(Order order)
    {
        var tempHolder = new BrokenRulesHolder();
        string rulePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Rules", "OrderValidations", SessionContext.CompanyID + ".r");
        
        using (RuleEngine engine = new RuleEngine(false)) // false = 檔案不存在不報錯
        {
            engine.BindRulePath(rulePath);
            engine.SetParameter("entity", order);
            engine.SetParameter("errors", tempHolder);
            engine.Process();
        }
        
        if (tempHolder.BrokenRules.Count > 0)
        {
            this.AddRange(tempHolder.BrokenRules);
            return false;
        }
        return true;
    }
}

BrokenRulesHolder 錯誤收集器


public class BrokenRulesHolder
{
    private List> brokenRules = new List>();
    
    public List> BrokenRules 
    { get { return brokenRules.AsReadOnly().ToList(); } }
    
    public void Add(string key, string msg) { brokenRules.Add(new KeyValuePair(key, msg)); }
    public void AddRange(List> rules) { brokenRules.AddRange(rules); }
    public void ClearBrokenRules() { brokenRules.Clear(); }
}

規則檔案語法完整說明

Declare 區段 (可選,最多一個)

declare 
    allowStores1=["a", "b"], 
    allowStores2=["c", "d"]
end declare
  • 全域變數定義與初始化
  • 支援 underscore.js 語法 (內建 underscore 1.5.2)

Rule 區段 (必須,一到多個)

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

執行邏輯轉換為 JavaScript


// 載入 underscore.js
// 載入 declare 區段轉換的 JS 代碼
if (rule1_condition) { 執行 rule1 then 區塊 }
else if (rule2_condition) { 執行 rule2 then 區塊 }
else if (rule3_condition) { 執行 rule3 then 區塊 }

架構優勢

傳統硬編碼A2D 規則引擎
修改需重新編譯部署規則檔案熱更新,無需重啟
僅開發人員可修改專案經理/實施顧問可維護
規則分散在程式碼中集中管理、版本控制、審計追蹤
多客戶需分支程式碼同一代碼基底,差異化規則檔案

擴展建議

  • 在規則檔案中引入自訂 JavaScript 函數庫
  • 整合規則版本管理與灰度發布機制
  • 建立規則可視化編輯器 (Web-based)
  • 支援決策表、決策樹等更豐富的規則表示

程式碼已整合至 A2D Framework:sourceforge.net/projects/a2dframework/

查看本欄目

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved