前言
源自于晓晨在成都.net社区群的一篇文章 《晓晨的ASP.NET Core 奇淫技巧之伪属性注入》
他的思路是 Ioc容器替换 ControllerActivator,因为只能在控制器内完成属性注入,意识心痒痒,就开笔写了这样一篇
先分析一下属性注入的思路
属性注入的核心就是通过动态代理完成注入,在这个过程中,对源实例的属性/字段注入实体
想了一下,最近几天沉迷学习,没有写点什么技术分享了,又想起之前学习AspectCore的过程,就打算基于AspectCore制作属性注入
设计思路如下
可以看见无论是默认的特性注入AOP流程,还是我们自定义的代理工厂类,核心都是通过拦截执行过程到自定义的过滤器
个人选择实现的方式是自定义工厂类,也可以根据代码,实现特性注入的方式注入属性
到属性注入这一步,就是查找自定义的特性,有注入的特性的,则完成字段/属性注入
实例实现
属性注入的特性
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] public class PropertyInjectAttribute: Attribute { }
这个特性,我们约束了只能打在字段/属性上面
自定义过滤器/过滤器工厂类
过滤器
internal class PropertyInjectInterceptor : IInterceptor { public bool AllowMultiple => true; public bool Inherited { get ; set; } public int Order { get; set; } public Task Invoke(AspectContext context, AspectDelegate next) { var instace = context.Implementation; var instanceType = instace.GetType(); var serviceProvider = context.ServiceProvider; var bindingFlag = BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public; foreach (var field in instanceType .GetFields(bindingFlag) .Where(_field => _field.GetCustomAttributes(typeof(PropertyInjectAttribute), true) != null && _field.GetCustomAttributes(typeof(PropertyInjectAttribute), true).Length > 0 && _field.FieldType.IsInterface ) ) { var value = field.GetReflector().GetValue(instace); if (value == null) { var service = serviceProvider.GetRequiredService(field.FieldType); field.GetReflector().SetValue(instace, service); } } foreach (var property in instanceType .GetProperties(bindingFlag) .Where(_property => _property.GetCustomAttributes(typeof(PropertyInjectAttribute), true) != null && _property.GetCustomAttributes(typeof(PropertyInjectAttribute), true).Length > 0 && _property.PropertyType.IsInterface ) ) { var value = property.GetReflector().GetValue(instace); if (value == null) { var service = serviceProvider.GetRequiredService(property.PropertyType); property.GetReflector().SetValue(instace, service); } } return next(context); } }
过滤器工厂类
public class PropertyInjectInterceptorFactory : InterceptorFactory { public override IInterceptor CreateInstance(IServiceProvider serviceProvider) { return serviceProvider.GetRequiredService<PropertyInjectInterceptor>(); } }
启用过滤器工厂类
services.AddScoped<PropertyInjectInterceptor>(); services.ConfigureDynamicProxy(config => { config.Interceptors.Add(new PropertyInjectInterceptorFactory()); }); return services.BuildDynamicProxyProvider();
编写测试例子
public interface IInterface { void Hello(); } internal class InterfaceService : IInterface { [PropertyInject] private IPropertyServer propertyServer; [PropertyInject] private IPropertyServer _propertyServer { get; set; } public void Hello() { Console.WriteLine("Hello"); } } [NonAspect] public interface IPropertyServer { } internal class PropertyServer: IPropertyServer { }
属性注入的实现,我不想再被AOP代理一次,就打上了NopAspect特性,如果不介意的话,也可以不打
后话
我隐隐约约记得AspectCore是自带了属性注入的,奈何最近几天没写C#代码了,有点想念,就自己撸上,重复造轮子了
分享嘛,思路最重要,使用而言,有成熟的轮子肯定不要自己造,学习的话,就要有勇于造轮子的心思
打个小广告
如果有技术交流可以加NCC的群 24791014、436035237,我在群里,有任何关于asp.net core方面的问题或者建议都可以与我交流,非常欢迎
附上晓晨的链接
《ASP.NET Core 奇淫技巧之伪属性注入》