于今天,功能终于完善度到比较满意的程度了
准备好好写一篇文章,而不是之前的流水账,分享一下最近这些天的踩坑
一开始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的知识