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

Enterprise Library Policy Injection Application Block 實戰 (三):自訂 CallHandler 完整開發流程——屬性與組態雙模式套用

     編輯:關於.NET

本文以「訂單驗證」為例,完整示範自訂 CallHandler 開發全流程:建立驗證邏輯、屬性模式套用、組態模式套用 (需 HandlerData + CallHandlerAssembler)、映射關係建立。

案例:訂單處理前驗證規則

  • 必須:訂單日期 ≤ 今日、至少一個訂單明細
  • 可選:供應商為合法清單、訂單總價等於明細金額加總

Step I:方案結構

方案結構

  • Artech.CustomCallHandlers.ClassLibrary:自訂 CallHandler、屬性、組態類別
  • Artech.CustomCallHandlers.ConsoleApp:測試專案
  • 參考:EnterpriseLibrary.Common、PolicyInjection、ObjectBuilder

Step II:輔助類別

public class Order
{
    public Guid OrderNo { get; set; }
    public DateTime OrderDate { get; set; }
    public string Supplier { get; set; }
    public IList<OrderItem> Items { get; set; } = new List<OrderItem>();
    public double TotalPrice { get; set; }
}

public class OrderItem
{
    public Guid ProductID { get; set; }
    public string ProductName { get; set; }
    public double UnitPrice { get; set; }
    public int Quantity { get; set; }
}

public class OrderValidationException : ApplicationException
{
    public OrderValidationException(string msg) : base(msg) { }
}

Step III:核心 CallHandler 實作

[ConfigurationElementType(typeof(OrderValidationCallHandlerData))]
public class OrderValidationCallHandler : ICallHandler
{
    public static IList<string> LegalSuppliers { get; } = new List<string> { "Company AAA", "BBB", "CCC" };

    public bool ValidateTotalPrice { get; set; }
    public bool ValidateSupplier { get; set; }

    public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
    {
        if (input.Inputs.Count == 0) return getNext()(input, getNext);
        var order = input.Inputs[0] as Order;
        if (order == null) return getNext()(input, getNext);

        // 必須驗證
        if (order.OrderDate > DateTime.Today)
            return input.CreateExceptionMethodReturn(new OrderValidationException("Order date > today"));
        if (order.Items.Count == 0)
            return input.CreateExceptionMethodReturn(new OrderValidationException("No items"));

        // 可選驗證
        if (ValidateSupplier && !LegalSuppliers.Contains(order.Supplier))
            return input.CreateExceptionMethodReturn(new OrderValidationException("Illegal supplier"));
        if (ValidateTotalPrice)
        {
            double sum = order.Items.Sum(i => i.Quantity * i.UnitPrice);
            if (sum != order.TotalPrice)
                return input.CreateExceptionMethodReturn(new OrderValidationException("Price mismatch"));
        }

        return getNext()(input, getNext); // 通過驗證,繼續管線
    }
}

關鍵點:CreateExceptionMethodReturn 短路管線拋出異常;getNext()(input, getNext) 傳遞給下一個 Handler 或目標方法。

Step IV:屬性模式套用

[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)]
public class OrderValidationCallHandlerAttribute : HandlerAttribute
{
    public bool ValidateTotalPrice { get; set; }
    public bool ValidateSupplier { get; set; }
    public override ICallHandler CreateHandler()
        => new OrderValidationCallHandler { ValidateTotalPrice = this.ValidateTotalPrice, ValidateSupplier = this.ValidateSupplier };
}

測試程式碼

public class OrderProcessor : MarshalByRefObject
{
    [OrderValidationCallHandlerAttribute] // 預設不啟用可選驗證
    public void ProcessOrder(Order order) => Console.WriteLine("Order processed!");

    public static Order CreateOrder(DateTime date, string supplier)
        => new Order { OrderNo = Guid.NewGuid(), OrderDate = date, Supplier = supplier, TotalPrice = 10000,
            Items = { new OrderItem { ProductName = "PC", UnitPrice = 6000, Quantity = 1 },
                      new OrderItem { ProductName = "Print", UnitPrice = 5000, Quantity = 2 } } };
}

class Program
{
    static void Main()
    {
        var proxy = PolicyInjection.Create<OrderProcessor>();
        // 測試三種失敗案例...
    }
}

預設僅必須驗證生效

加上屬性參數啟用可選驗證:

[OrderValidationCallHandlerAttribute(ValidateSupplier = true, ValidateTotalPrice = true)]

全驗證生效

Step V:組態模式套用 (HandlerData + Assembler)

[Assembler(typeof(OrderValidationCallHandlerAssembler))]
public class OrderValidationCallHandlerData : CallHandlerData
{
    [ConfigurationProperty("validateSupplier", DefaultValue = false)]
    public bool ValidateSupplier { get => (bool)base["validateSupplier"]; set => base["validateSupplier"] = value; }

    [ConfigurationProperty("validateTotalPrice", DefaultValue = false)]
    public bool ValidateTotalPrice { get => (bool)base["validateTotalPrice"]; set => base["validateTotalPrice"] = value; }
}

public class OrderValidationCallHandlerAssembler : IAssembler<ICallHandler, CallHandlerData>
{
    public ICallHandler Assemble(IBuilderContext context, CallHandlerData config, IConfigurationSource source, ConfigurationReflectionCache cache)
    {
        var data = config as OrderValidationCallHandlerData;
        return new OrderValidationCallHandler { ValidateSupplier = data.ValidateSupplier, ValidateTotalPrice = data.ValidateTotalPrice };
    }
}

Step VI:組態檔設定與驗證

<policyInjection>
  <policies>
    <add name="Policy">
      <matchingRules>
        <add type="...MemberNameMatchingRule" name="Member Name Matching Rule">
          <matches><add match="ProcessOrder" /></matches>
        </add>
      </matchingRules>
      <handlers>
        <add type="Artech.CustomCallHandlers.OrderValidationCallHandler, Artech.CustomCallHandlers"
             name="OrderValidationCallHandler" validateSupplier="true" validateTotalPrice="true" />
      </handlers>
    </add>
  </policies>
</policyInjection>
  • matchingRules:使用 MemberNameMatchingRule 比對方法名 ProcessOrder
  • handlers:直接指定型別與屬性值

移除屬性、套用組態後執行,結果與屬性模式完全一致。

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