Dora.Interception,為.NET Core度身打造的AOP框架 [4]:與依賴註入框架的無縫集成
一、IInterceptable<T>
由於.NET Core總是采用IServiceProvider接口表示的DI容器來提供註入的依賴服務對象,現在我們得將原始的目標對象轉換成能夠被攔截代理對象,為此我們提供了一個泛型的服務接口IInterceptable<T>,它的Proxy屬性返回的就是這麽一個代理對象。
public interface IInterceptable<T> where T: class { T Proxy { get; } }
由於著了一個幫助我們提供可攔截代理的IInterceptable<T>服務,我們就可以在需要攔截目標類型的地方按照如下的方式註入該服務,並利用其Proxy屬性得到這個可被攔截的代理。
public class HomeController : Controller { private readonly ISystemClock _clock; public HomeController(IInterceptable<ISystemClock> clockAccessor) { _clock = clockAccessor.Proxy; Debug.Assert(typeof(SystemClock) != _clock.GetType()); } }
二、讓IServiceProvider直接代理對象
在被依賴類型的構造函數中註入IInterceptable<T>服務的編程方式總顯得有點別扭,這要求所有具有AOP需求的組件都需要依賴Dora.Interception,這無疑是不現實的。我們最終需要解決的還是如何讓IServiceProvider直接提供可被攔截的代理對象,為此我對.NET Core依賴註入框架的源代碼作了一點很小的改動。這個經過簡單修改的IServiceProvider實現類型就是如下這個InterceptableServiceProvider 類型。至於具體修改了什麽,並不是一兩句話就能說清楚的,這涉及到整個依賴註入框架的設計,有興趣有查看源代碼。
internal sealed class InterceptableServiceProvider : IServiceProvider, IDisposable, IServiceProviderEngineCallback { internal InterceptableServiceProvider(IEnumerable<ServiceDescriptor> serviceDescriptors, ServiceProviderOptions options, IInterceptingProxyFactory interceptingProxyFactory); public void Dispose(); public object GetService(Type serviceType); void IServiceProviderEngineCallback.OnCreate(IServiceCallSite callSite); void IServiceProviderEngineCallback.OnResolve(Type serviceType, IServiceScope scope); }
我們在Startup類型的ConfigureServices方法中,調用IServiceCollection的擴展方法BuildInterceptableServiceProvider創建的就是這麽一個InterceptableServiceProvider 對象。
public class Startup { public IServiceProvider ConfigureServices(IServiceCollection services) { return services ... .BuildInterceptableServiceProvider(); } ... }
三、服務註冊
Dora.Interception所需的服務註冊都是通過調用IServiceCollection的擴展方法AddInterception來完成的,由於AddInterception會調整現有的服務註冊以支持上面介紹的IInterceptable<T>服務,所以AddInterception方法的調用需要放在所有服務註冊結束之後。創建InterceptableServiceProvider的BuildInterceptableServiceProvider方法內部會調用AddInterception方法,但是不會對現有的服務註冊作任何修改。
public static class ServiceCollectionExtensions { public static IServiceCollection AddInterception(this IServiceCollection services, Action<InterceptionBuilder> configure = null); public static IServiceProvider BuildInterceptableServiceProvider(this IServiceCollection services, Action<InterceptionBuilder> configure = null); public static IServiceProvider BuildInterceptableServiceProvider(this IServiceCollection services, bool validateScopes, Action<InterceptionBuilder> configure = null); }
AddInterception和BuildInterceptableServiceProvider方法均定義了一個Action<InterceptionBuilder>類型的參數,我們可以利用它對註冊的服務做進一步定制。比如如果我們需要實現自定義的攔截器註冊方式,只需要將自定義的IInterceptorProviderResolver對象添加到InterceptorProviderResolvers 屬性表示的集合中即可。
public class InterceptionBuilder { public InterceptionBuilder(IServiceCollection services); public InterceptorProviderResolverCollection InterceptorProviderResolvers { get; } public IServiceCollection Services { get; } }
[1]:更加簡練的編程體驗
[2]:基於約定的攔截器定義方式
[3]:多樣性的攔截器應用方式
[4]:與依賴註入框架的深度整合
[5]:對攔截機制的靈活定制
Dora.Interception,為.NET Core度身打造的AOP框架 [4]:與依賴註入框架的無縫集成