ASP.NET Core 奇淫技巧之伪属性注入的实现

 更新时间:2021年9月22日 09:59  点击:2152

一.前言

开局先唠嗑一下,许久未曾更新博客,一直在调整自己的状态,去年是我的本命年,或许是应验了本命年的多灾多难,过得十分不顺,不论是生活上还是工作上。还好当我度过了所谓的本命年后,许多事情都在慢慢变好,我将会开始恢复更新博客,争取恢复到以前的速度上(因为工作比较忙,所以这个过程可能需要一段时间)。

二.关于属性注入

说到属性注入,我们就不得不提一下 DI(Dependency Injection),即依赖注入,用过 ASP.NET Core 的同学相信对这个词不会陌生。ASP.NET Core 自带了一个IOC容器,且程序运行也是基于这个容器建立起来的,在 Startup 里的 ConfigureServices 方法就是向容器注册类型。最直白的讲,我们在 ASP.NET Core 中,想使用某个类型的时候可以不用自己去 new,可以由容器通过构造方法来注入具体的实现类型,而我们一般在构造方法上定义的依赖类型都是接口,而不是去依赖具体的实现,这里就体现了 SOLID 原则中的依赖倒置原则(DIP)。这也是IOC(Inversion of Control),即控制反转,不直接依赖具体实现,将依赖交给容器去控制。上述几者是具有一定的关联关系的,DIP 是一种软件设计原则,IOC 是 DIP 的具体实现方式,DI 是 IOC 的一种实现方式。

在依赖注入时,我们最常用的便是通过构造方法注入,还有另一种方式那便是属性注入。

关于属性注入,如果在网上搜索,大部分内容都是不推荐使用,或者说慎重使用的,因为属性注入会造成类型的依赖关系隐藏,测试不友好等,我也同意这种说法,属性注入可以使用,但是要谨慎,不能盲目使用。我的原则:在封装框架(搭架子)时可以使用,但不能大范围使用,只有必须使用属性注入来达到效果的地方才会使用,用来提高使用框架时的编码效率,来达到一些便利,脱离框架层面,编写业务代码时,不得使用。

在 ASP.NET Core 中,自带的容器是不支持属性注入的,但是可以通过替换容器,如:Autofac 等来实现。今天我分享的方法不是使用替换容器,而是通过几行代码来实现属性注入的效果,我称为“伪属性注入”。

三.属性注入解决的痛点

以下介绍的痛点是我在实际编码过程中遇到的一些,如果还有其他的,欢迎在评论和我交流

我所遇到的痛点,我归纳为三条:

1.减少常用的类型的重复注入代码,使构造方法看起来更为简洁,提高阅读性。

2.减少或消除因构造方法注入造成子类继承后的 base 调用链。

3.并非是满足第一条或第二条就需要使用属性注入来解决,只有当第一、二条发生的情况到达一定的数量。

第一条:

以日志 ILogger<T> 为例,我们在 Controller 或者 应用服务层(Application Service)等编写业务的地方可能会常用,那么我们可能会在大部分的 Controller 或者 Application Service 的构造方法里写一句注入,例:

这里只是以日志来举例,我们还能遇到和日志这种相同的类型,每个 Controller 等都要注入一堆这种共同的类型,代码编写起来也比较麻烦,如果多了以后还影响代码阅读。

有何解决办法,那就是定义一个基类,然后通过属性提供给子类,以 Controller 为例:

第二条:

在上面的Controller基类注入 ILogger,然后设置了 Logger 属性,这样子类就可以使用 Logger 属性来使用日志。

这样做每次都要调用 base 将依赖对象传递给基类,如果继承关系有多层,将会造成更大的影响。

注意:本文演示只以日志来举例,如果只有一个ILogger我觉得还可以忍受,实际情况中并非只有一个,比如本地化等等。博主不提倡有上面演示情况的就用属性注入,当到达一定数量才使用,比如在 Controller 或者应用服务这种数量多的对象以及当这些对象需要的共同的注入类型达到一定数量。

四. 伪属性注入核心思想

依托于 ASP.NET Core 自带的容器,在 Resolve Service 时,为需要“属性注入”的属性进行赋值,可以使用 自带容器提供的 ImplementationFactory 来实现。

五. 为 Controller 实现伪属性注入

Controller 的实现较为特殊,Controller 默认是不会通过自带容器来 Resolve&Activate 的,是通过MVC自身管理的,但是微软提供了这样的方法:

services.AddControllers().AddControllersAsServices();

可以通过调用 AddControllersAsServices() 方法来让 Controller 使用自带容器,其主要源代码如下

根据第四小节的思想,我们需要 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 来方便的使用文中我所描述的“伪属性注入”,最后反复想了想,还是觉得不做。如果要使用完全的属性注入可以替换使用第三方容器,本文所述旨在不想引入第三方容器,且想在部分地方来达到属性注入的效果,因为属性注入这个东西也不推荐大范围使用。

本文来源于我在工作中的一些灵感总结,我在看 ControllerActivator 源码时的突发奇想,最近工作虽然忙,但是知识确实积攒了不少,在后面与大家一一分享。

姊妹篇:ASP.NET Core 奇淫技巧之动态WebApi

到此这篇关于ASP.NET Core 奇淫技巧之伪属性注入的实现的文章就介绍到这了,更多相关ASP.NET Core 伪属性注入内容请搜索猪先飞以前的文章或继续浏览下面的相关文章希望大家以后多多支持猪先飞!

作者:晓晨Master(李志强)

文章链接:https://www.cnblogs.com/stulzq/p/12610026.html

[!--infotagslink--]

相关文章

  • ASP.NET购物车实现过程详解

    这篇文章主要为大家详细介绍了ASP.NET购物车的实现过程,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2021-09-22
  • .NET Core下使用Kafka的方法步骤

    这篇文章主要介绍了.NET Core下使用Kafka的方法步骤,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-09-22
  • 在ASP.NET 2.0中操作数据之七十二:调试存储过程

    在开发过程中,使用Visual Studio的断点调试功能可以很方便帮我们调试发现程序存在的错误,同样Visual Studio也支持对SQL Server里面的存储过程进行调试,下面就让我们看看具体的调试方法。...2021-09-22
  • 详解.NET Core 3.0 里新的JSON API

    这篇文章主要介绍了详解.NET Core 3.0 里新的JSON API,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-09-22
  • ASP.NET Core根据环境变量支持多个 appsettings.json配置文件

    这篇文章主要介绍了ASP.NET Core根据环境变量支持多个 appsettings.json配置文件,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-09-22
  • 记一次EFCore类型转换错误及解决方案

    这篇文章主要介绍了记一次EFCore类型转换错误及解决方案,帮助大家更好的理解和学习使用asp.net core,感兴趣的朋友可以了解下...2021-09-22
  • 详解ASP.NET Core 中基于工厂的中间件激活的实现方法

    这篇文章主要介绍了ASP.NET Core 中基于工厂的中间件激活的实现方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-09-22
  • asp.net通过消息队列处理高并发请求(以抢小米手机为例)

    这篇文章主要介绍了asp.net通过消息队列处理高并发请求(以抢小米手机为例),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-09-22
  • Underscore源码分析

    Underscore 是一个 JavaScript 工具库,它提供了一整套函数式编程的实用功能,但是没有扩展任何 JavaScript 内置对象。这篇文章主要介绍了underscore源码分析相关知识,感兴趣的朋友一起学习吧...2016-01-02
  • ASP.NET 2.0中的数据操作:使用两个DropDownList过滤的主/从报表

    在前面的指南中我们研究了如何显示一个简单的主/从报表, 该报表使用DropDownList和GridView控件, DropDownList填充类别,GridView显示选定类别的产品. 这类报表用于显示具有...2016-05-19
  • ASP.NET单选按钮控件RadioButton常用属性和方法介绍

    RadioButton又称单选按钮,其在工具箱中的图标为 ,单选按钮通常成组出现,用于提供两个或多个互斥选项,即在一组单选钮中只能选择一个...2021-09-22
  • 详解.NET Core 使用HttpClient SSL请求出错的解决办法

    这篇文章主要介绍了.NET Core 使用HttpClient SSL请求出错的解决办法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧...2021-09-22
  • ASP.NET中iframe框架点击左边页面链接 右边显示链接页面内容

    这篇文章主要介绍了ASP.NET中iframe框架点击左边页面链接,右边显示链接页面内容的实现代码,感兴趣的小伙伴们可以参考一下...2021-09-22
  • 创建一个完整的ASP.NET Web API项目

    ASP.NET Web API具有与ASP.NET MVC类似的编程方式,ASP.NET Web API不仅仅具有一个完全独立的消息处理管道,而且这个管道比为ASP.NET MVC设计的管道更为复杂,功能也更为强大。下面创建一个简单的Web API项目,需要的朋友可以参考下...2021-09-22
  • ASP.NET连接MySql数据库的2个方法及示例

    这篇文章主要介绍了ASP.NET连接MySql数据库的2个方法及示例,使用的是MySQL官方组件和ODBC.NET,需要的朋友可以参考下...2021-09-22
  • Asp.Net使用Bulk实现批量插入数据

    这篇文章主要介绍了Asp.Net使用Bulk实现批量插入数据的方法,对于进行asp.net数据库程序设计非常有借鉴价值,需要的朋友可以参考下...2021-09-22
  • 在ASP.NET 2.0中操作数据之二十九:用DataList和Repeater来显示数据

    本文主要讲解ASP.NET 2.0中如何使用DataList 和 Repeater 来呈现数据,DataList包含一个table标记,而Repeater不会添加任何额外的代码,个人在实际开发中更推荐使用Repeater。...2021-09-22
  • Asp.net中获取DataTable选择第一行某一列值

    这篇文章主要介绍了获取DataTable选择第一行某一列值,需要的朋友可以参考下...2021-09-22
  • Asp.net动态生成html页面的方法分享

    这篇文章介绍了Asp.net动态生成html页面的方法,有需要的朋友可以参考一下...2021-09-22
  • ASP.Net中的async+await异步编程的实现

    这篇文章主要介绍了ASP.Net中的async+await异步编程的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-09-22