• Dora.Interception,为.NET Core度身打造的AOP框架 [4]:与依赖注入框架的无缝集成


      Dora.Interception最初的定位就是专门针对.NET Core的AOP框架,所以在整个迭代过程中我大部分是在做减法。对于.NET Core程序开发来说,依赖注入已经成为无处不在并且“深入骨髓”的东西,不论是在进行业务应用的开发,还是进行基础组件的开发,依赖注入是实现“松耦合”最为理想的方式(没有之一)。对于绝大部分AOP框架来说,它们最终都会体现为创建一个能够拦截的“代理对象”来实现对方法调用的拦截,但是.NET Core中针对服务实例的提供完全由通过IServiceProvider接口表示的DI容器来接管,所以Dora.Interception必须将两者无缝地集成在一起。与依赖注入框架的集成不仅仅体现在对可被拦截的代理对象的创建,同样应用在了针对拦截器的定义和注册上。

    一、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
    如果你想及时得到个人撰写文章以及著作的消息推送,或者想看看个人推荐的技术资料,可以扫描左边二维码(或者长按识别二维码)关注个人公众号)。
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
     
    ********转载:https://www.cnblogs.com/artech/p/dora-interception-04.html
  • 相关阅读:
    在非MFC的win 32程序里面能够使用CString类
    一 VC2008环境中ICE的配置
    二 示例程序一
    三 ICE开发初级研究
    VC断点不可用的问题
    Ice笔记-利用Ice::Application类简化Ice应用
    GetCurrentDirectory、SetCurrentDirectory和GetModuleFileName
    Xcopy参数介绍
    COM组件开发实践(八)---多线程ActiveX控件和自动调整ActiveX控件大小(下)
    JackSon fasterxml学习
  • 原文地址:https://www.cnblogs.com/linybo/p/10053032.html
Copyright © 2020-2023  润新知