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

Enterprise Library Policy Injection Application Block 進階 (四):實作可排序 CallHandler Pipeline 解決執行順序控制難題

     編輯:關於.NET

Policy Injection Application Block (PIAB) 提供優雅的 AOP 實作,但原生版本無法控制多個 CallHandler 在同一方法上的執行順序。本文透過修改原始碼實作可排序 CallHandler Pipeline,引入 Ordinal 屬性決定執行優先序。

為何需要 CallHandler 排序?

典型案例:ValidationHandler (參數驗證) → TransactionEnlistHandler (交易登記) → AuditLoggingHandler (稽核記錄)。

  • 驗證必須最先執行,失敗則不進入後續邏輯
  • 交易需包含稽核記錄,故交易登記需在稽核前
  • 原生 PIAB 依組態/屬性宣告順序執行,無法靈活控制

核心機制:Method Interception 與 Handler Pipeline

PIAB 透過 RealProxy 攔截方法呼叫,建構 HandlerPipeline (CallHandler 串聯鏈)。切入點:Pipeline 建構完成後,依 Ordinal 重新排序。

修改兩個核心類別

1. HandlerPipeline:暴露 Handlers 集合供排序

public class HandlerPipeline
{
    private List<ICallHandler> handlers;
    public List<ICallHandler> Handlers
    {
        get { return handlers; }
        set { handlers = value; }
    }
    // ... 原有成員
}

2. InterceptingRealProxy:Invoke 中呼叫排序邏輯

public HandlerPipeline ResortHandlers(HandlerPipeline pipeline)
{
    var sequentialPipeline = new HandlerPipeline();
    var handlerOrdinalPairList = new Dictionary<ICallHandler, int>();
    var handlers = pipeline.Handlers.ToArray();
    var ordinals = new int[handlers.Length];

    for (int i = 0; i < handlers.Length; i++)
    {
        var handler = handlers[i];
        var memberInfos = handler.GetType().GetMember("Ordinal");
        if (memberInfos.Length == 0) { ordinals[i] = int.MaxValue; continue; }
        var prop = memberInfos[0] as PropertyInfo;
        if (prop == null) { ordinals[i] = int.MaxValue; continue; }
        ordinals[i] = (int)prop.GetValue(handler, null);
    }

    // 氣泡排序 (簡單示範,實務可用 LINQ OrderBy)
    for (int i = 0; i < handlers.Length - 1; i++)
        for (int j = i + 1; j < handlers.Length; j++)
            if (ordinals[i] > ordinals[j])
            {
                Swap(ref handlers[i], ref handlers[j]);
                Swap(ref ordinals[i], ref ordinals[j]);
            }

    return new HandlerPipeline(handlers);
}

public override IMessage Invoke(IMessage msg)
{
    // ... 取得 pipeline ...
    pipeline = ResortHandlers(pipeline); // 關鍵:排序後再執行
    // ... 執行 pipeline ...
}

建議:定義抽象基底類別 OrderedCallHandlerBase 內建 Ordinal 屬性,避免反射效能損耗。

驗證測試:自訂 CallHandler 與屬性

public class CustomHandlerA : ICallHandler
{
    public int Ordinal { get; set; } = int.MaxValue;
    public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
    {
        Console.WriteLine("CustomHandlerA invoked!");
        return getNext()(input, getNext);
    }
}

[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)]
public class ACustomHandlerAttribute : HandlerAttribute
{
    public int Ordinal { get; set; }
    public override ICallHandler CreateHandler()
        => new CustomHandlerA { Ordinal = this.Ordinal };
}

// CustomHandlerB / BCustomHandlerAttribute 同理

套用屬性指定順序

public class PolicyInjectionType : MarshalByRefObject
{
    [BCustomHandlerAttribute(Ordinal = 1)]  // 先執行
    [ACustomHandlerAttribute(Ordinal = 2)]  // 後執行
    public void DoSomething()
    {
        Console.WriteLine("Target method invoked!");
    }
}

執行結果驗證

順序 1: B → A → Target

調換 Ordinal 值:

[BCustomHandlerAttribute(Ordinal = 2)]
[ACustomHandlerAttribute(Ordinal = 1)]

順序 2: A → B → Target

輸出證實順序受 Ordinal 控制,解決原生 PIAB 無法排序的缺憾。

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