這里所謂的與第三方AOP框架的整合不是說改變Dora.Interception現有的編程,而是恰好相反,即在不改變現有編程模式下采用第三方AOP框架或者自行實現的攔截機制。雖然我們默認提供基於IL Emit實現方式,並且對IL指令進行了深度的優化,但是如果我們真的具有更好的選擇,我們可以通過簡單的擴展完成對底層攔截機制改變。
一、IInterceptingProxyFactory
對於Dora.Interception來說,方法調用之所有能夠被攔截的根源在於我們改變了服務實例的提供方式,原來的對象被替換成了可被攔截的代理對象。針對代理對象的提供體現在如下這個IInterceptingProxyFactory接口上。如果提供類型體現為一個接口,Wrap方法會被調用來創建一個封裝目標對象的代理(如果不需要被攔截,則直接返回目標對象);如果提供類型體現為一個類型,Create方法則被用來實現對代理對象的創建,如果不需要被攔截,方法提供的后面兩個參數會被用來提供目標對象。
public interface IInterceptingProxyFactory { IServiceProvider ServiceProvider { get; } object Wrap(Type typeToIntercept, object target); object Create(Type typeToIntercept, IServiceProvider serviceProvider, Func<object> targetAccessor = null); }
二、InterceptingProxyFactoryBase
Dora.Interception提供了如下一個實現了IInterceptingProxyFactory接口的基類InterceptingProxyFactoryBase。后者幫助我們實現針對攔截器的解析,解析后的攔截器體現為一個InterceptorDecoration對象。作為它的派生類型只需要實現兩個受保護的虛方法Wrap和Create根據解析出來的攔截器實現可被攔截的代理對象的創建。
public abstract class InterceptingProxyFactoryBase : IInterceptingProxyFactory { public IInterceptorResolver InterceptorResolver { get; } public IServiceProvider ServiceProvider { get; } public InterceptingProxyFactoryBase(IInterceptorResolver interceptorResolver, IServiceProvider serviceProvider); public object Create(Type typeToIntercept, IServiceProvider serviceProvider, Func<object> targetAccessor = null); public object Wrap(Type typeToIntercept, object target); protected virtual bool CanIntercept(Type typeToIntercept); protected abstract object Wrap(Type typeToIntercept, object target, InterceptorDecoration interceptors); protected abstract object Create(Type typeToIntercept, IServiceProvider serviceProvider, InterceptorDecoration interceptors); }
如果所示的是InterceptorDecoration, 我們可以得到應用到目標類型中所有方法(包括屬性的Get和Set方法)上的攔截器(實際上所有攔截器按照指定順序構建而成的攔截器管道,最終體現為一個類型為InterceptorDelegate 的委托對象)。
public sealed class InterceptorDecoration { public InterceptorDelegate GetInterceptor(MethodInfo methodInfo); public MethodInfo GetTargetMethod(MethodInfo methodInfo); public bool IsInterceptable(MethodInfo methodInfo); public IReadOnlyDictionary<int, InterceptorDelegate> Interceptors { get; } public bool IsEmpty { get; } public IReadOnlyDictionary<MethodInfo, MethodBasedInterceptorDecoration> MethodBasedInterceptors { get; } public IReadOnlyDictionary<PropertyInfo, PropertyBasedInterceptorDecoration> PropertyBasedInterceptors { get; } } public class MethodBasedInterceptorDecoration { public InterceptorDelegate Interceptor { get; } public MethodInfo Method { get; } } public class PropertyBasedInterceptorDecoration { public PropertyInfo Property { get; } public MethodBasedInterceptorDecoration GetMethodBasedInterceptor { get; } public MethodBasedInterceptorDecoration SetMethodBasedInterceptor { get; } }
自定義的IInterceptingProxyFactory實現只需要按照普通的服進行注冊即可。
三、針對Castle的集成
由於Castle原生的框架並沒有提供針對Task的支持,所以我們利用另一個名為Castle.Core.AsyncInterceptor將Castle的攔截實現整合到Dora.Interception。具體的實現體現在如下這個DynamicProxyFactory中。該類型對應的NuGet包為“Dora.Interception.Castle”。
public class DynamicProxyFactory : InterceptingProxyFactoryBase { public DynamicProxyFactory(IInterceptorResolver interceptorResolver, IServiceProvider serviceProvider); protected override object Create(Type typeToIntercept, IServiceProvider serviceProvider, InterceptorDecoration interceptors); protected override object Wrap(Type typeToIntercept, object target, InterceptorDecoration interceptors); }
如果需要采用基於Caslte的攔截實現機制,我們只需要做如下的設置即可。
public class Startup { public void ConfigureServices(IServiceCollection services) { services ... AddInterception(builder=>builder.SetCastleDynamicProxy()); } ... }
或者
public class Startup { public IServiceProvider ConfigureServices(IServiceCollection services) { return services ... .BuildInterceptableServiceProvider(builder=>builder.SetCastleDynamicProxy()); } ... }
[1]:更加簡練的編程體驗
[2]:基於約定的攔截器定義方式
[3]:多樣性的攔截器應用方式
[4]:與依賴注入框架的深度整合
[5]:對攔截機制的靈活定制