NCoreCoder.Aop详解

于今天,功能终于完善度到比较满意的程度了

准备好好写一篇文章,而不是之前的流水账,分享一下最近这些天的踩坑


 

一开始AOP选的微软提供的DispatchProxy

关于这个,有大佬的文章,可以看看,了解一下

https://www.cnblogs.com/ElderJames/p/implement-simple-Aop-using-a-dotnet-core-library-System-Reflection-DispatchProxy.html

初步完成后,发现几个大问题,异步不支持,不支持构造器注入,代理类必须是继承DispatchProxy的公开类

我就想到我偶像Lemon大佬的著作AspectCore了,依稀记得是Emit构建的代理类

也有代码可以参考学习,那就开干,前后四天多的时间,终于完工

下面介绍一下我的AOP组件 NCoreCoder.Aop的使用以及高级应用


 

简单的使用NCoreCoder.Aop

NCoreCoder.Aop支持依赖注入,用依赖注入的方式完成代理类和接口的关联

支持.Net Core 3.0以及以下的依赖注入方式

示例

    public interface IMyClass
    {
        void TestVoid();
        int TestInt();
        Task TestAsync();
        Task<int> TestIntAsync();
    }

    [JitInject]
    internal class MyClass : IMyClass
    {
        public void TestVoid()
        {
            Console.WriteLine("TestVoid");
        }

        public int TestInt()
        {
            Console.WriteLine("TestInt");

            return 100;
        }

        public Task TestAsync()
        {
            Console.WriteLine("TestAsync");

            return Task.CompletedTask;
        }

        public Task<int> TestIntAsync()
        {
            Console.WriteLine("TestIntAsync");

            return Task.FromResult(100);
        }
    }

打上JitInject特性是证明这个类需要实现代理

这里就只是构建代理类,没有方法并走代理流程,代理支持 同步API、异步无返回值API、异步有返回值API

要拦截的方法,默认是继承JitAopAttribute,打特性方式完成拦截器注入

打在继承的实现类上

比如

    [AttributeUsage(AttributeTargets.Method)]
    internal class TestJitAttribute : JitAopAttribute
    {
        public override void Before(MethodReflector method, object instance, params object[] param)
        {
        }

        public override void After(MethodReflector method, object instance, params object[] param)
        {
        }

        public override Task BeforeAsync(MethodReflector method, object instance, params object[] param)
        {return Task.CompletedTask;
        }

        public override Task AfterAsync(MethodReflector method, object instance, params object[] param)
        {return Task.CompletedTask;
        }
    }

在需要拦截的方法上,打上TestJit即可

        [TestJit]
        public void TestVoid()
        {
            Console.WriteLine("TestVoid");
        }

        public int TestInt()
        {
            Console.WriteLine("TestInt");

            return 100;
        }

        public Task TestAsync()
        {
            Console.WriteLine("TestAsync");

            return Task.CompletedTask;
        }

        public Task<int> TestIntAsync()
        {
            Console.WriteLine("TestIntAsync");

            return Task.FromResult(100);
        }
    }

这样TestVoid方法就要走AOP流程了

Asp.Net Core 3.0以下

因为Asp.Net Core 3.0以下的Startup.ConfigService方法支持直接修改返回值变成IServiceProvider

所以在Asp.Net Core 3.0以下,依赖注入都是在Startup.ConfigService里面修改IServiceProvider到自定义的IServiceProvider完成替换依赖注入容器和流程的效果,比如Autofac

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc();
            //略略略
        }

改为

        public IServiceProvider ConfigureServices(IServiceCollection services)
        {
            services.AddMvc();
            //略略略
            service.AddSingleton<IMyClass, MyClass>();

            //修改Ioc容器流程
            return service.BuilderJit();
        }

Asp.Net Core 3.0

Asp.Net Core 3.0的替换依赖注入流程变了

无法再修改Startup.ConfigService返回值了,只要不是void,运行就抛出异常

查看的Program.CreateHostBuilder

        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.UseStartup<Startup>();
                });

改为

        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .UseServiceProviderFactory(new JitServiceProviderFactory()) //新增
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.UseStartup<Startup>();
                });

这里可以保持原有依赖注入,也可以增加一个方法

        public void ConfigureContainer(JitAopBuilder builder)
        {
            builder.Add<IMyClass, MyClass>(ServiceLifetime.Singleton);
        }

测试Aop

            var service = new ServiceCollection();

            service.AddSingleton<IMyClass, MyClass>();

            var serviceProvider = service.BuilderJit();

            TypeBuilderFactory.Instance.Save();

            var myclass = serviceProvider.GetRequiredService<IMyClass>();

            Task.Factory.StartNew(async () =>
            {
                myclass.TestVoid();
                var result1 = myclass.TestInt();

                await myclass.TestAsync();
                var result2 = await myclass.TestIntAsync();
            });

            Console.ReadLine();

我们运行看看myclass对象是什么~

 

不是原有的MyClass对象


高级扩展

我们现在如果要针对不同流程,而不是默认的Before->After

那么我们就需要自定义一个IAopActors了

我们默认的JitAopAttribute的流程就是一个默认DefaultAopActors

 

编写一个公开的类,继承自IAopActors

IAopActors接口如下

 

然后再接口上打上特性AopActorsAttribute

特性的构造参数是Type对应了自定义的AopActors的Type

    public class TestActors : IAopActors
    {
        public object Execute(AopContext context)
        {
            throw new NotImplementedException();
        }

        public Task<TResult> ExecuteAsync<TResult>(AopContext context)
        {
            throw new NotImplementedException();
        }

        public Task InvokeAsync(AopContext context)
        {
            throw new NotImplementedException();
        }
    }
    [AopActors(typeof(TestActors))]
    public interface IMyClass
    {
        void TestVoid();
        int TestInt();
        Task TestAsync();
        Task<int> TestIntAsync();
    }

个人文笔不好,如有疑问,可以加“.Net应用程序框架交流” 群号386092459 欢迎到群里和我反馈Bug或者建议、交流Aop设计和Emit的知识

posted @ 2019-09-27 14:25  沉迷代码的萌新  阅读(527)  评论(1编辑  收藏  举报