【ASP.NET Core】依赖注入高级玩法——如何注入多个服务实现类
依赖注入在 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】依赖注入高级玩法——如何注入多个服务实现类相关推荐
- ASP.NET Core依赖注入初识与思考
一.前言 在上一篇中,我们讲述了什么是控制反转(IoC)以及通过哪些方式实现的.这其中,我们明白了,「控制反转(IoC)」 是一种软件设计的模式,指导我们设计出更优良,更具有松耦合的程序,而具体的实现 ...
- ASP.NET Core依赖注入最佳实践,提示技巧
分享翻译一篇Abp框架作者(Halil İbrahim Kalkan)关于ASP.NET Core依赖注入的博文. 在本文中,我将分享我在ASP.NET Core应用程序中使用依赖注入的经验和建议. ...
- ASP.NET Core依赖注入深入讨论
这篇文章我们来深入探讨ASP.NET Core.MVC Core中的依赖注入,我们将示范几乎所有可能的操作把依赖项注入到组件中. 依赖注入是ASP.NET Core的核心,它能让您应用程序中的组件增强 ...
- ASP.NET Core依赖注入容器中的动态服务注册
介绍 在ASP.NET Core中,每当我们将服务作为依赖项注入时,都必须将此服务注册到ASP.NET Core依赖项注入容器.但是,一个接一个地注册服务不仅繁琐且耗时,而且容易出错.因此,在这里,我 ...
- SkyWalking之高级玩法
导读 SkyWalking是基于javaagent的两大字节码操作工具之一的Byte Buddy实现的无侵入APM(application performance monitor) 系统,目前项目在A ...
- Redis高级玩法之利用SortedSet实现多维度排序的方法
说明:本次实践基于Redis版本3.2.11. 关于SortedSet 首先,我们都知道Redis的SortedSet是可以根据score进行排序的,以手机应用商店的热门榜单排序为例,根据下载量倒序排 ...
- 微软推出的Prompt高级玩法,包括小样本和任务分解等,简直不要太详细:Azure OpenAI 的提示工程技术
搜索 打开App 微软推出的Prompt高级玩法,包括小样本和任务分解等,简直不要太详细:Azure OpenAI 的提示工程技术 8 小时前 ChatGPT云炬学长 ChatGPT云炬学长 关注 ...
- 12面魔方公式图解法_【高级篇】(三)三阶魔方CFOP高级玩法之——F2L
一.F2L这一步要干什么 1.先了解一下"棱角对"和"槽位"的概念 棱角对:即由一个棱块和一个角块构成,是F2L的基本单元(共四组) 槽位:给"棱角对 ...
- Vim的几个高级玩法
文章目录 vim的几种模式 扩展命令模式命令: 命令模式高频命令: 命令模式进阶命令: vim高级玩法 小结: 在Linux中编辑文件的场景非常之多,掌握一些关键命令和技巧.能够大大提高效率,使用体 ...
最新文章
- [lwip-users] memp_malloc: out of memory in pool TCP_PCB
- win7 64-bit minifilter
- 正则表达式真的很骚,可惜你不会写!
- js 获取 select的option的 id值
- C#基础知识学习(2)string类中的方法
- 关于Java中获取当前系统时间
- Captaris Workflow开发系列课程介绍。
- Grace Ex助力区块链数字资产迈向全新未来
- 14岁少年打赏主播6万多元 后称自己行为无效起诉火山小视频要求返还
- IIS优化-解决IIS访问速度慢问题
- 服务器字段长度修改,postgresql 修改字段长度的操作
- Python语言程序设计基础-题库
- 主机甲和主机乙之间使用后退N帧协议(GBN)传输数据,甲的发送窗口为1000,数据帧长为1000字节,信道带宽为100Mb/s,乙每收到一个数据帧......[数据传输率]错题总结
- 谷歌浏览器怎么关闭硬件加速?
- 一文看尽Stata绘图
- [数据压缩作业1]利用Audacity分析浊音、清音、爆破音|RGB文件三通道分量的熵计算
- 共享文件夹无法打开——服务器存储空间不足,无法处理此命令
- Windows中的未处理异常
- 蓝桥杯每日一练专栏导读
- Scrapy爬虫入门教程五 Selectors(选择器)
热门文章
- Ceph Upstream 添加 InfiniBand RDMA 互联支持
- ThinkPHP + Ajax 实现2级联动下拉菜单
- 36.centos 安装文泉驿字体
- php面向对象编程开发,php面向对象编程之对象
- edittext 监听无效_Android中EditText 设置 imeOptions 无效问题的解决方法
- 2016设置方框的尺寸_四种模板脚手架分类、优缺点及参数设置对比
- Verilog赋值间延迟语句与赋值内延迟语句比较
- 如何解决C/C++中stack overflow问题
- 从源码分析DEARGUI之add_menu
- Django-model中的Querysets