前言
源自於曉晨在成都.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 奇淫技巧之偽屬性注入》