在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
一.前言 开局先唠嗑一下,许久未曾更新博客,一直在调整自己的状态,去年是我的本命年,或许是应验了本命年的多灾多难,过得十分不顺,不论是生活上还是工作上。还好当我度过了所谓的本命年后,许多事情都在慢慢变好,我将会开始恢复更新博客,争取恢复到以前的速度上(因为工作比较忙,所以这个过程可能需要一段时间)。 二.关于属性注入 说到属性注入,我们就不得不提一下 DI(Dependency Injection),即依赖注入,用过 ASP.NET Core 的同学相信对这个词不会陌生。ASP.NET Core 自带了一个IOC容器,且程序运行也是基于这个容器建立起来的,在 Startup 里的 在依赖注入时,我们最常用的便是通过构造方法注入,还有另一种方式那便是属性注入。 关于属性注入,如果在网上搜索,大部分内容都是不推荐使用,或者说慎重使用的,因为属性注入会造成类型的依赖关系隐藏,测试不友好等,我也同意这种说法,属性注入可以使用,但是要谨慎,不能盲目使用。我的原则:在封装框架(搭架子)时可以使用,但不能大范围使用,只有必须使用属性注入来达到效果的地方才会使用,用来提高使用框架时的编码效率,来达到一些便利,脱离框架层面,编写业务代码时,不得使用。 在 ASP.NET Core 中,自带的容器是不支持属性注入的,但是可以通过替换容器,如:Autofac 等来实现。今天我分享的方法不是使用替换容器,而是通过几行代码来实现属性注入的效果,我称为“伪属性注入”。 三.属性注入解决的痛点 以下介绍的痛点是我在实际编码过程中遇到的一些,如果还有其他的,欢迎在评论和我交流 我所遇到的痛点,我归纳为三条: 1.减少常用的类型的重复注入代码,使构造方法看起来更为简洁,提高阅读性。 2.减少或消除因构造方法注入造成子类继承后的 base 调用链。 3.并非是满足第一条或第二条就需要使用属性注入来解决,只有当第一、二条发生的情况到达一定的数量。 第一条: 以日志 这里只是以日志来举例,我们还能遇到和日志这种相同的类型,每个 Controller 等都要注入一堆这种共同的类型,代码编写起来也比较麻烦,如果多了以后还影响代码阅读。 有何解决办法,那就是定义一个基类,然后通过属性提供给子类,以 Controller 为例: 第二条: 在上面的Controller基类注入 ILogger,然后设置了 Logger 属性,这样子类就可以使用 Logger 属性来使用日志。 这样做每次都要调用 base 将依赖对象传递给基类,如果继承关系有多层,将会造成更大的影响。 注意:本文演示只以日志来举例,如果只有一个ILogger我觉得还可以忍受,实际情况中并非只有一个,比如本地化等等。博主不提倡有上面演示情况的就用属性注入,当到达一定数量才使用,比如在 Controller 或者应用服务这种数量多的对象以及当这些对象需要的共同的注入类型达到一定数量。 四. 伪属性注入核心思想 依托于 ASP.NET Core 自带的容器,在 Resolve Service 时,为需要“属性注入”的属性进行赋值,可以使用 自带容器提供的 五. 为 Controller 实现伪属性注入 Controller 的实现较为特殊,Controller 默认是不会通过自带容器来 Resolve&Activate 的,是通过MVC自身管理的,但是微软提供了这样的方法: services.AddControllers().AddControllersAsServices(); 可以通过调用 根据第四小节的思想,我们需要 Controller Resolve 时,来对属性进行赋值,那么我们需要改造 Controller 激活器。 定义 Controller 基类 Controller 继承基类 改造 Controller 激活器 可以看到我们改造的代码也就几行。 替换默认 Controller 激活器 services.AddControllers().AddControllersAsServices(); services.Replace(ServiceDescriptor.Transient<IControllerActivator, XcServiceBasedControllerActivator>()); //替换默认 Controller 激活器 运行测试 测试正常,如需其他属性的“属性注入”,参考日志这样做就行了。 六. 为 Application Service 实现伪属性注入 只是以 Application Service 来作为讲解,同理可举一反三到其他地方。Application Service 属于领域驱动分层架构中的一层,如不了解,可自行查找资料。 定义应用服务基类接口 public interface IAppService { ILogger Logger { get; set; } } public class AppService:IAppService { public ILogger Logger { get; set; } } 定义具体服务,以 User 服务为例 public interface IUserAppService:IAppService { void Create(); } public class UserAppService : AppService,IUserAppService { public void Create() { Logger.LogInformation("来自 Application Service 的日志"); } } 定义特殊的注册服务的方法,以便实现 Resolve 为 Logger 赋值 public static class ServiceExtensions { public static IServiceCollection AddApplicationService<TService, TImpl>(this IServiceCollection services) where TService:IAppService where TImpl:AppService { services.AddApplicationService(typeof(TService), typeof(TImpl)); return services; } // 可以反射程序集调用此方法实现批量自动注册应用服务 public static IServiceCollection AddApplicationService(this IServiceCollection services, Type serviceType,Type implType) { services.AddTransient(serviceType, sp => { //获取服务实现的实例 var implInstance = ActivatorUtilities.CreateInstance(sp, implType); ; if (implInstance is AppService obj) { //为 Logger 赋值 obj.Logger= sp.GetRequiredService<ILoggerFactory>().CreateLogger(implType); } return implInstance; }); return services; } 注册测试服务 Controller 注入测试服务 运行测试 七.结束 其实到本文写完,我都在想,要不要封装一个组件,发布到 Nuget 来方便的使用文中我所描述的“伪属性注入”,最后反复想了想,还是觉得不做。如果要使用完全的属性注入可以替换使用第三方容器,本文所述旨在不想引入第三方容器,且想在部分地方来达到属性注入的效果,因为属性注入这个东西也不推荐大范围使用。 本文来源于我在工作中的一些灵感总结,我在看 姊妹篇:ASP.NET Core 奇淫技巧之动态WebApi 到此这篇关于ASP.NET Core 奇淫技巧之伪属性注入的实现的文章就介绍到这了,更多相关ASP.NET Core 伪属性注入内容请搜索极客世界以前的文章或继续浏览下面的相关文章希望大家以后多多支持极客世界! 作者:晓晨Master(李志强) 文章链接:https://www.cnblogs.com/stulzq/p/12610026.html |
请发表评论