一、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]:对拦截机制的灵活定制
微信公众账号:大内老A
微博:www.weibo.com/artech
如果你想及时得到个人撰写文章以及著作的消息推送,或者想看看个人推荐的技术资料,可以扫描左边二维码(或者长按识别二维码)关注个人公众号)。
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。