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

Enterprise Library Policy Injection Application Block 架構深度解析 (二):MBR/RealProxy 攔截機制、Handler Pipeline 與 PolicyInjector 工廠完整原理

     編輯:關於.NET

深度剖析 PIAB 內部實現:.NET Remoting MBR 架構、自訂 RealProxy 方法攔截、CallHandler Pipeline 串聯執行、PolicyInjector 工廠建構 Transparent Proxy 全流程。

背景知識:MBR、ObjRef、RealProxy、TransparentProxy

  • MBR (MarshalByRefObject):跨 AppDomain 以參考傳遞,CLR 產生 ObjRef (含 URI、型別階層、介面等)
  • RealProxy:依 ObjRef 建立,處理真正呼叫邏輯 (可繼承自訂)
  • TransparentProxy:依 RealProxy 建立,客戶端直接呼叫此 Proxy,轉發至 RealProxy
  • 同一 AppDomain 內亦可運作,避免跨域效能損耗,PIAB 即利用此機制

方法攔截與自訂 RealProxy

呼叫鏈:Client → TransparentProxy → RealProxy.Invoke() → Target。在 RealProxy.Invoke 中插入 Pre/Post 作業即實現 AOP。

簡易示範:自訂 RealProxy 註入 Pre/Post 操作

public class MyRealProxy<T> : RealProxy
{
    private T _target;
    public MyRealProxy(T target) : base(typeof(T)) { _target = target; }

    public override IMessage Invoke(IMessage msg)
    {
        Console.WriteLine("Pre-operation injected");
        var callMsg = (IMethodCallMessage)msg;
        var ret = callMsg.MethodBase.Invoke(_target, callMsg.Args);
        Console.WriteLine("Post-operation injected");
        return new ReturnMessage(ret, null, 0, null, callMsg);
    }
}

public static class PolicyInjectionFactory
{
    public static T Create<T>()
    {
        var inst = Activator.CreateInstance<T>();
        var rp = new MyRealProxy<T>(inst);
        return (T)rp.GetTransparentProxy();
    }
}

簡易攔截執行結果

驗證:Business Logic 僅一行,Crosscutting Concern 由 Proxy 注入,完美分離。

CallHandler Pipeline:串聯多個横切關注點

一個方法常需多個 Handler:Authorization → Auditing → Transaction → Exception Handling → Logging。

PIAB 將同一方法的所有 Handler 串成 HandlerPipeline:

Handler Pipeline 結構

核心介面與類別

public delegate IMethodReturn InvokeHandlerDelegate(IMethodInvocation input, GetNextHandlerDelegate getNext);
public delegate InvokeHandlerDelegate GetNextHandlerDelegate();

public interface IMethodInvocation
{
    IParameterCollection Arguments { get; }
    IParameterCollection Inputs { get; }
    IDictionary InvocationContext { get; }
    MethodBase MethodBase { get; }
    object Target { get; }
    IMethodReturn CreateExceptionMethodReturn(Exception ex);
    IMethodReturn CreateMethodReturn(object returnValue, params object[] outputs);
}

public interface ICallHandler
{
    IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext);
}

public class HandlerPipeline
{
    private List<ICallHandler> handlers;
    public IMethodReturn Invoke(IMethodInvocation input, InvokeHandlerDelegate target)
    {
        if (handlers.Count == 0) return target(input, null);
        int idx = 0;
        return handlers[0].Invoke(input, delegate {
            idx++;
            return idx < handlers.Count 
                ? new InvokeHandlerDelegate(handlers[idx].Invoke) 
                : target;
        });
    }
}

遞迴委派鏈:每個 Handler 執行完呼叫 getNext 執行下一個,最後執行 target (目標方法)。

PIAB 真實 RealProxy:InterceptingRealProxy

public class InterceptingRealProxy : RealProxy, IRemotingTypeInfo
{
    private Dictionary<MethodBase, HandlerPipeline> memberHandlers;
    private readonly object target;

    public override IMessage Invoke(IMessage msg)
    {
        var callMsg = (IMethodCallMessage)msg;
        var pipeline = memberHandlers.ContainsKey(callMsg.MethodBase) 
            ? memberHandlers[callMsg.MethodBase] 
            : new HandlerPipeline();

        var invocation = new RemotingMethodInvocation(callMsg, target);
        return ((RemotingMethodReturn) pipeline.Invoke(invocation, delegate {
            try {
                var ret = callMsg.MethodBase.Invoke(target, invocation.Arguments);
                return invocation.CreateMethodReturn(ret, invocation.Arguments);
            } catch (TargetInvocationException ex) {
                return invocation.CreateExceptionMethodReturn(ex.InnerException);
            }
        })).ToMethodReturnMessage();
    }
}
  • memberHandlers:方法 → Pipeline 字典,初始化時建構
  • 依 MethodBase 取得對應 Pipeline 執行

PolicyInjector 工廠:建構 Proxy 與初始化 Pipeline

public abstract class PolicyInjector
{
    public PolicySet Policies { get; set; }
    public TObject Create<TObject>(params object[] args) => (TObject)Create(typeof(TObject), typeof(TObject), args);
    public TInterface Create<TObject, TInterface>(params object[] args) => (TInterface)Create(typeof(TObject), typeof(TInterface), args);

    public object Create(Type typeToCreate, Type typeToReturn, params object[] args)
    {
        var policiesFor = Policies.GetPoliciesFor(typeToCreate);
        EnsureTypeIsInterceptable(typeToReturn, policiesFor);
        return DoCreate(typeToCreate, typeToReturn, policiesFor, args);
    }

    protected override object DoWrap(object instance, Type typeToReturn, PolicySet policiesForThisType)
    {
        if (PolicyInjector.PolicyRequiresInterception(policiesForThisType))
        {
            var proxy = new InterceptingRealProxy(UnwrapTarget(instance), typeToReturn, policiesForThisType);
            return proxy.GetTransparentProxy();
        }
        return instance;
    }
}

預設 PolicyInjector:RemotingPolicyInjector

  • 單例模式從組態載入
  • 初始化:先解析組態定義的 Policy,再用反射掃描屬性定義的 Policy
  • 注意:同一 Policy 若在組態與屬性重複定義,會產生重複 Handler (設計上可議)

攔截型別條件

public override bool TypeSupportsInterception(Type t)
    => typeof(MarshalByRefObject).IsAssignableFrom(t) || t.IsInterface;

故目標類別必須繼承 MarshalByRefObject 或實作介面。

整體類別圖

PIAB 核心類別圖

Remoting 架構圖

Remoting 架構圖2

下一篇將介紹自訂 CallHandler 開發實戰。

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