依赖注入在 ASP.NET Core 中起中很重要的作用,也是一种高大上的编程思想,它的总体原则就是:俺要啥,你就给俺送啥过来。服务类型的实例转由容器自动管理,无需我们在代码中显式处理。

因此,有了依赖注入后,你的编程思维就得变一变了。在过去,许多功能性的类型(比如一个加密解密的类),我们都喜欢将其定义为静态(static),而有了依赖注入,你就要避免使用静态类型,应该交由服务容器帮你管理,只要你用好了,你会发现依赖注入是很方便的。

依赖注入的初级玩法,也是比较标准的玩法,此种玩法有两种模式:

1、十代单传模式:一个接口对应一个类,比如先定义接口 IA、IB,随后,类A实现 IA,类B 实现 IB。一对一。也可以是抽象类(或基类)E,然后 F 继承 E 类。

2、断子绝孙模式:直接就写一个类,不考虑派生,直接就添加到服务容器中。

来,看个例子。

我先定义个接口。

    public interface IPlayGame{void Play();}

然后,写一个类来实现它。

    public class NBPlayGame : IPlayGame{public void Play(){Console.WriteLine("全民打麻药。");}}

我们知道,所谓服务类,其实就是普通类,这些类一般用于完成某些功能,比如计算 MD5 值。接着呢,还记得 Startup 类有个 ConfigureServices 方法吧,对,就在这厮里面把我们刚刚那个服务进行注册(就是添加到 ServiceCollection 集合中)。

        public void ConfigureServices(IServiceCollection services){services.AddTransient<IPlayGame, NBPlayGame>();}

添加的时候很简单,类型一对一,IPlayGame 接口与 NBPlayGame 类对应。添加时有三种方法你可以调用,实际上对应着,服务类在容器中的生命周期。

AddSingleton:单个实例,这是寿命最长的,与天同寿。整个应用程序中仅用一个实例。

AddTransient:这个是最短命的,可能是天天晚上加班熬夜,死得很快。此种情况下,服务类的实例是用的时候创建,用完后直接销毁。

AddScoped:这个比较难理解。它的生命周期在单个请求内,包括客户端与服务器之间随后产生的子请求,反正只要请求的会话结束了,就会清理。

然后,你就可以进行注入了,比如在中间件,在控制器,或者在其他服务类的构造函数上(中间件是在 Invoke / InvokeAsync 方法上)进行实例接收。

现在来用一下,写一个中间件。

    public class TestMiddleware{public TestMiddleware(RequestDelegate next) { }public Task InvokeAsync(HttpContext context, IPlayGame game){game.Play();return Task.CompletedTask;}}

已注册的服务会注入到 InvokeAsync 方法的参数中。注意第一个参数是 HttpContext,这是必须参数,后面的是注入的参数。

最后,在 Startup 类的 Configure 方法中就可以 use 这个中间件了。

        public void Configure(IApplicationBuilder app){app.UseMiddleware<TestMiddleware>();}

运行后,Play 方法调用,在控制台中输出以下结果。

“断子绝孙”模式,不使用接口规范,直接写功能类。

    public class DoSomething{public string GetMessage() => "你好,刚才 Boss 找你。";}

注册服务时更简单。

        public void ConfigureServices(IServiceCollection services){services.AddScoped<DoSomething>();}

在 Configure 方法中进行注入。

        public void Configure(IApplicationBuilder app, DoSomething thing){Console.WriteLine(thing.GetMessage());}

运行后,输出结果如下。

在容器中,使用 ServiceDescriptor 类来存储服务类型相关的信息。其中,ServiceType 表示的是服务的类型,如果服务是有接口与实现类的,那么这个属性指的是接口的类型,实现类的类型信息由 ImplementationType 属性存储。如果没有接口,直接只定义类型,那么这个类型的信息就存到 ServiceType 属性上,ImplementationType 属性不使用。

上面这些例子中,ServiceType 是 IPlayGame 接口相关信息,ImplementationType 是 NBPlayGame 类的信息。如果像上面 DoSomething 类的情况,则 ServiceType 为 DoSomething 相关的信息,ImplementationType 为空。

接下来,咱们看高级玩法。

定义一个接口。

    public interface IDemoService{string Version { get; }void Run();}

然后,有两个类实现这个接口。

    public class DemoService1 : IDemoService{public string Version => "v1";public void Run(){Console.WriteLine("第一个服务实现类。");}}public class DemoService2 : IDemoService{public string Version => "v2";public void Run(){Console.WriteLine("第二个服务实现类。");}}

然后,我们注册服务。

        public void ConfigureServices(IServiceCollection services){services.AddTransient<IDemoService, DemoService1>();services.AddTransient<IDemoService, DemoService2>();}

然后我们照例,接收注入,咱们依旧使用中间件的方法参数接收。

    public class DemoMiddleware{public DemoMiddleware(RequestDelegate next){// 由于程序约定,此构造函数必须提供。
        }public async Task InvokeAsync(HttpContext context, IDemoService sv){await context.Response.WriteAsync(sv.Version);}}

然后,在 Startup.Configure 方法中使用该中间件。

        public void Configure(IApplicationBuilder app, DoSomething thing){app.UseMiddleware<DemoMiddleware>();}

运行之后,你发现问题了,看看输出。

出事了,参数仅能接收到最后注册的实现类型实例,也就是 DemoService2 类。所以就看到网上有不少朋友发贴问了,.NET Core 是不是不支持多个服务实现类的注入?这难倒了很多人。

实话告诉你,Core Core 兄是支持注入多个实现类的实例的。

下面,老周介绍两种解决方法(其实有三种,还有一种不太好弄,尤其是你对 Core 兄不熟的时候,所以我说两种,基本够用)。

方法一、接收 IServiceProvider 类型的注入。

        public async Task InvokeAsync(HttpContext context, IServiceProvider provider){StringBuilder sb = new StringBuilder();foreach (var sv in provider.GetServices<IDemoService>()){sb.Append($"{sv.Version}<br/>");}await context.Response.WriteAsync(sb.ToString());}

只要能接收到 IServiceProvider 所引用的实例,就能通过 GetServices 方法获取多个服务实例。

方法二,这种方法老周很推荐,更简单,直接注入 IEnumerable<T> 类型,本例中就是 IEnumerable<IDemoService>。

        public async Task InvokeAsync(HttpContext context, IEnumerable<IDemoService> svs){StringBuilder sb = new StringBuilder();foreach (var sv in svs){sb.Append($"{sv.Version}<br/>");}await context.Response.WriteAsync(sb.ToString());}

IEnumerable<T> 的妙处就是可以 foreach ,这样你也能访问多个实例,而且必要时还可以联合 LINQ 一起耍。

运行结果如下。

不要问我是怎么发现的,反正我告诉你了,你用就是了。

好了,今天的话题就到这儿了,3166。

转载于:https://www.cnblogs.com/tcjiaan/p/8732848.html

【ASP.NET Core】依赖注入高级玩法——如何注入多个服务实现类相关推荐

  1. ASP.NET Core依赖注入初识与思考

    一.前言 在上一篇中,我们讲述了什么是控制反转(IoC)以及通过哪些方式实现的.这其中,我们明白了,「控制反转(IoC)」 是一种软件设计的模式,指导我们设计出更优良,更具有松耦合的程序,而具体的实现 ...

  2. ASP.NET Core依赖注入最佳实践,提示技巧

    分享翻译一篇Abp框架作者(Halil İbrahim Kalkan)关于ASP.NET Core依赖注入的博文. 在本文中,我将分享我在ASP.NET Core应用程序中使用依赖注入的经验和建议. ...

  3. ASP.NET Core依赖注入深入讨论

    这篇文章我们来深入探讨ASP.NET Core.MVC Core中的依赖注入,我们将示范几乎所有可能的操作把依赖项注入到组件中. 依赖注入是ASP.NET Core的核心,它能让您应用程序中的组件增强 ...

  4. ASP.NET Core依赖注入容器中的动态服务注册

    介绍 在ASP.NET Core中,每当我们将服务作为依赖项注入时,都必须将此服务注册到ASP.NET Core依赖项注入容器.但是,一个接一个地注册服务不仅繁琐且耗时,而且容易出错.因此,在这里,我 ...

  5. SkyWalking之高级玩法

    导读 SkyWalking是基于javaagent的两大字节码操作工具之一的Byte Buddy实现的无侵入APM(application performance monitor) 系统,目前项目在A ...

  6. Redis高级玩法之利用SortedSet实现多维度排序的方法

    说明:本次实践基于Redis版本3.2.11. 关于SortedSet 首先,我们都知道Redis的SortedSet是可以根据score进行排序的,以手机应用商店的热门榜单排序为例,根据下载量倒序排 ...

  7. 微软推出的Prompt高级玩法,包括小样本和任务分解等,简直不要太详细:Azure OpenAI 的提示工程技术

    搜索 打开App 微软推出的Prompt高级玩法,包括小样本和任务分解等,简直不要太详细:Azure OpenAI 的提示工程技术 8 小时前 ChatGPT云炬学长 ChatGPT云炬学长 ​关注 ...

  8. 12面魔方公式图解法_【高级篇】(三)三阶魔方CFOP高级玩法之——F2L

    一.F2L这一步要干什么 1.先了解一下"棱角对"和"槽位"的概念 棱角对:即由一个棱块和一个角块构成,是F2L的基本单元(共四组) 槽位:给"棱角对 ...

  9. Vim的几个高级玩法

    文章目录 vim的几种模式 扩展命令模式命令: 命令模式高频命令: 命令模式进阶命令: vim高级玩法 小结:  在Linux中编辑文件的场景非常之多,掌握一些关键命令和技巧.能够大大提高效率,使用体 ...

最新文章

  1. [lwip-users] memp_malloc: out of memory in pool TCP_PCB
  2. win7 64-bit minifilter
  3. 正则表达式真的很骚,可惜你不会写!
  4. js 获取 select的option的 id值
  5. C#基础知识学习(2)string类中的方法
  6. 关于Java中获取当前系统时间
  7. Captaris Workflow开发系列课程介绍。
  8. Grace Ex助力区块链数字资产迈向全新未来
  9. 14岁少年打赏主播6万多元 后称自己行为无效起诉火山小视频要求返还
  10. IIS优化-解决IIS访问速度慢问题
  11. 服务器字段长度修改,postgresql 修改字段长度的操作
  12. Python语言程序设计基础-题库
  13. 主机甲和主机乙之间使用后退N帧协议(GBN)传输数据,甲的发送窗口为1000,数据帧长为1000字节,信道带宽为100Mb/s,乙每收到一个数据帧......[数据传输率]错题总结
  14. 谷歌浏览器怎么关闭硬件加速?
  15. 一文看尽Stata绘图
  16. [数据压缩作业1]利用Audacity分析浊音、清音、爆破音|RGB文件三通道分量的熵计算
  17. 共享文件夹无法打开——服务器存储空间不足,无法处理此命令
  18. Windows中的未处理异常
  19. 蓝桥杯每日一练专栏导读
  20. Scrapy爬虫入门教程五 Selectors(选择器)

热门文章

  1. Ceph Upstream 添加 InfiniBand RDMA 互联支持
  2. ThinkPHP + Ajax 实现2级联动下拉菜单
  3. 36.centos 安装文泉驿字体
  4. php面向对象编程开发,php面向对象编程之对象
  5. edittext 监听无效_Android中EditText 设置 imeOptions 无效问题的解决方法
  6. 2016设置方框的尺寸_四种模板脚手架分类、优缺点及参数设置对比
  7. Verilog赋值间延迟语句与赋值内延迟语句比较
  8. 如何解决C/C++中stack overflow问题
  9. 从源码分析DEARGUI之add_menu
  10. Django-model中的Querysets