tnblog
首页
视频
资源
登录

ASP.NET Core 依赖注入(基础)[学习笔记]

6505人阅读 2020/5/8 10:21 总访问:3465066 评论:4 收藏:0 手机
分类: .net后台框架

.netcore

ASP.NET Core 依赖注入(基础)[学习笔记]


环境准备


项目结构

项目结构

服务类


GenericService.cs
  1. public interface IGenericService<T>
  2. {
  3. }
  4. public class GenericService<T> : IGenericService<T>
  5. {
  6. public T Data { get; private set; }
  7. public GenericService(T data)
  8. {
  9. this.Data = data;
  10. }
  11. }
IService.cs
  1. public interface IService
  2. {
  3. Guid GetId();
  4. }
MyScopedService.cs
  1. public interface IMyScopedService { }
  2. public class MyScopedService : IMyScopedService
  3. {
  4. }
MySingletonService.cs
  1. public interface IMySingletonService
  2. {
  3. }
  4. public class MySingletonService : IMySingletonService
  5. {
  6. }
MyTransientService.cs
  1. public interface IMyTransientService
  2. {
  3. }
  4. public class MyTransientService : IMyTransientService
  5. {
  6. }
OrderService.cs
  1. public interface IOrderService
  2. {
  3. }
  4. public class OrderService : IOrderService
  5. {
  6. }
  7. public class OrderServiceEx : IOrderService
  8. {
  9. }

控制器类

WeatherForecastController.cs
  1. [ApiController]
  2. [Route("[controller]")]
  3. public class WeatherForecastController : ControllerBase
  4. {
  5. private readonly ILogger<WeatherForecastController> _logger;
  6. public WeatherForecastController(ILogger<WeatherForecastController> logger)
  7. {
  8. _logger = logger;
  9. }
  10. [HttpGet("GetService")]
  11. public int GetService([FromServices]IMySingletonService singleton1,
  12. [FromServices]IMySingletonService singleton2,
  13. [FromServices]IMyTransientService transient1,
  14. [FromServices]IMyTransientService transient2,
  15. [FromServices]IMyScopedService scoped1,
  16. [FromServices]IMyScopedService scoped2)
  17. {
  18. Console.WriteLine($"singleton1:{singleton1.GetHashCode()}");
  19. Console.WriteLine($"singleton2:{singleton2.GetHashCode()}");
  20. Console.WriteLine($"transient1:{transient1.GetHashCode()}");
  21. Console.WriteLine($"transient2:{transient2.GetHashCode()}");
  22. Console.WriteLine($"scoped1:{scoped1.GetHashCode()}");
  23. Console.WriteLine($"scoped2:{scoped2.GetHashCode()}");
  24. Console.WriteLine($"========GetService 请求结束=======");
  25. return 1;
  26. }
  27. [HttpGet("GetService2")]
  28. public int GetService2([FromServices]IMySingletonService singleton1,
  29. [FromServices]IMySingletonService singleton2,
  30. [FromServices]IMyTransientService transient1,
  31. [FromServices]IMyTransientService transient2,
  32. [FromServices]IMyScopedService scoped1,
  33. [FromServices]IMyScopedService scoped2)
  34. {
  35. Console.WriteLine($"singleton1:{singleton1.GetHashCode()}");
  36. Console.WriteLine($"singleton2:{singleton2.GetHashCode()}");
  37. Console.WriteLine($"transient1:{transient1.GetHashCode()}");
  38. Console.WriteLine($"transient2:{transient2.GetHashCode()}");
  39. Console.WriteLine($"scoped1:{scoped1.GetHashCode()}");
  40. Console.WriteLine($"scoped2:{scoped2.GetHashCode()}");
  41. Console.WriteLine($"========GetService 2 请求结束=======");
  42. return 1;
  43. }
  44. /// <summary>
  45. /// 获取 Service
  46. /// </summary>
  47. /// <param name="services"></param>
  48. /// <returns></returns>
  49. [HttpGet("GetServiceList")]
  50. public int GetServiceList([FromServices]IEnumerable<IOrderService> services)
  51. {
  52. foreach (var item in services)
  53. {
  54. Console.WriteLine($"Get Servic instances:{item.ToString()}:{item.GetHashCode()}");
  55. }
  56. return 1;
  57. }


依赖注入


介绍


参考jesse大佬的:https://www.cnblogs.com/jesse2013/p/di-in-aspnetcore.html
依赖:依赖于抽象,而不是具体的实现。
注入:注入体现的是一个IOC(控制反转的的思想)。

容器:统一管理依赖的地方,大部分容器的内部实现方式,都是工厂模式+反射
IOC:我的理解是实例化不由自身来决定了,而是交给容器来进行实例了。举例:
Userinfo user = 容器.create(“user”) as Userinfo;
DI :通过容器实例对象时,给对象赋值

(有意见请评论)


注册服务不同生命周期的服务


Startup.cs
  1. #region 注册服务不同生命周期的服务
  2. services.AddSingleton<IMySingletonService, MySingletonService>();
  3. services.AddScoped<IMyScopedService, MyScopedService>();
  4. services.AddTransient<IMyTransientService, MyTransientService>();
  5. #endregion
注册方式 效果
Singleton 单例,永远都是那一个固定的实例进行注入
Transient 注入的实例永远不同
Scoped 请求的方法不同,注入的实例就不相同

结果

生命周期


花式注册

  1. services.AddSingleton<IOrderService>(new OrderService()); //直接注入实例
  2. //services.AddSingleton<IOrderService, OrderServiceEx>();
  3. //services.AddSingleton<IOrderService, OrderService>();
  4. //services.AddSingleton<IOrderService, OrderService>();
  5. //工厂模式
  6. //services.AddSingleton<IOrderService>(serviceProvider =>
  7. //{
  8. // return new OrderServiceEx();
  9. //});
  10. //services.AddScoped<IOrderService>(serviceProvider =>
  11. //{
  12. // return new OrderServiceEx();
  13. //});


尝试注册

  1. //我们的服务已经注册过了,就不能再注册了
  2. //services.TryAddSingleton<IOrderService, OrderServiceEx>();
  3. //相同类型的服务接口,如果实现不同则可以注册进去
  4. //services.TryAddEnumerable(ServiceDescriptor.Singleton<IOrderService, OrderServiceEx>());
  5. //services.TryAddEnumerable(ServiceDescriptor.Singleton<IOrderService, OrderServiceEx>());
  6. //services.TryAddEnumerable(ServiceDescriptor.Singleton<IOrderService>(new OrderServiceEx()));
  7. //services.TryAddEnumerable(ServiceDescriptor.Singleton<IOrderService>(p =>
  8. //{
  9. // return new OrderServiceEx();
  10. //}));

尝试注入

尝试注入

实现不同就尝试注册

实现不同就尝试注册

移除和替换注册

  1. //替换
  2. services.Replace(ServiceDescriptor.Singleton<IOrderService, OrderServiceEx>());
  3. //删除
  4. services.RemoveAll<IOrderService>();

替换

替换

移除

移除

注册泛型模板

  1. services.AddSingleton(typeof(IGenericService<>), typeof(GenericService<>));

Scoped变Singleton的问题

在一个需要注入Singleton单例注入的服务中,如果该服务的注入是Scoped,那么该服务的注入会变成Singleton一样的生命周期,在规定内释放的时候无法进行释放。
解决这个的方式是使用ServiceProvider的扩展BuildServiceProvider方法,该方法对其注入有严格的验证,我们来分析一下该方法。

该扩展有3个重载方法;我们发现都是通过配置选项ServiceProviderOptions对服务范围进行的检验,我们接着来看ServiceProviderOptions配置类中的属性

我们只看重要的两个属性ValidateScopesValidateOnBuild。表示

属性 描述
ValidateScopes 当设置为True时开启针对范围的检测。
ValidateOnBuild 当设置为True时检测构造是否能够提供服务。

ValidateScopes属性的示例

  1. public interface ITest { }
  2. public interface IBoobar { }
  3. public class Test : ITest { }
  4. public class Boobar : IBoobar
  5. {
  6. public Boobar(ITest test)
  7. {
  8. _test = test;
  9. }
  10. public ITest _test { get; }
  11. }
  1. var services = new ServiceCollection();
  2. // 创建单例ITest
  3. services.AddSingleton<ITest, Test>();
  4. // 添加范围注册
  5. services.AddScoped<IBoobar, Boobar>();
  6. var root = services.BuildServiceProvider(new ServiceProviderOptions
  7. {
  8. ValidateScopes = true
  9. });
  10. // 获取服务
  11. root.GetService<IBoobar>();

我们可以看到它直接抛出InvalidOperationException异常,无法解析…;当我们反转一下注册的方式,它是以单例模式Transient为主,如果需要提供的服务不是TransientScoped将会注册失败

  1. var services = new ServiceCollection();
  2. // 创建单例ITest
  3. services.AddScoped<ITest, Test>();
  4. // 添加范围注册
  5. services.AddSingleton<IBoobar, Boobar>();
  6. var root = services.BuildServiceProvider(new ServiceProviderOptions
  7. {
  8. ValidateScopes = true
  9. });
  10. // 子容器获取ITest服务成功
  11. root.CreateScope().ServiceProvider.GetService<ITest>();
  12. // 子容器获取IBoobar服务失败
  13. root.CreateScope().ServiceProvider.GetService<IBoobar>();
  14. // 根容器获取失败
  15. root.GetService<ITest>();
  16. // 根容器获取失败
  17. root.GetService<IBoobar>();

ValidateOnBuild属性的示例

  1. public class Boobar : IBoobar
  2. {
  3. private Boobar()
  4. {
  5. }
  6. }
  7. static void Main(string[] args)
  8. {
  9. var services = new ServiceCollection();
  10. // 添加单例注册
  11. services.AddSingleton<IBoobar, Boobar>();
  12. var root = services.BuildServiceProvider(new ServiceProviderOptions
  13. {
  14. ValidateOnBuild = true
  15. });
  16. // 根容器获取失败
  17. root.GetService<IBoobar>();
  18. }

在服务注册时,便报错了。因为Boobar只有一个私有构造,无法进行实例。


项目地址


GitHub: https://github.com/AiDaShi/GeekTimeLearning


简单的依赖注入的架构



课程推荐




欢迎加群讨论技术,1群:677373950(满了,可以加,但通过不了),2群:656732739

评价

忘掉过去式

2020/5/8 13:44:53

优秀[哈哈]

2020/5/13 23:01:40 回复

是伍尚金哇_v

2020/11/16 8:55:17

老哥,什么时候出个github使用的入门到正常提交项目日常的文章呢

2020/12/30 9:46:56 回复

asp.net core2.0 依赖注入 AddTransient与AddScoped的区别

asp.net core主要提供了三种依赖注入的方式其中AddTransient与AddSingleton比较好区别AddTransient瞬时模式:每次都获取一...

c使用unity实现依赖注入一:依赖注入介绍

依赖注入的简单介绍直接关联是这样滴,耦合性超高的。这里有一个设计原则:依赖于抽象,而不是具体的实现试想一下如果做了...

c使用unity实现依赖注入二:基本使用

使用Unity实现依赖注入的基本步骤:1:需要创建一个容器2:给容器添加类与类之间的关系(控制反转)3: 在需要的地方从容器里...

c使用unity实现依赖注入三:unity常用生命周期

常用的生命周期有瞬时模式,单利模式,每个线程一个对象模式等。一:TransientLifetimeManagerTransientLifetimeManager模...

c使用unity实现依赖注入四:unity配置文件注入

需要用到的配置文件一:先向xml申明一下unity的配置文件所在的实现类&lt;configSections&gt; &lt;sectionname=&quot;unity...

net core使用依赖注入来装载EF的上下文对象

妹子情人节快乐~.net core中用了不少的依赖注入,官方文档中也推荐使用。这样使用依赖注入来管理ef对象,还是比较科学,比如...

net core依赖注入

添加注入首先需要添加好一个注入:其实添加好类与类之间的关系,在ConfigureServices中添加注入services.AddTransient&lt;I...

net core过滤器。net core过滤器中获取依赖注入对象。net core过滤器中使用依赖注入。ServiceFilter 

虽然对象都可以直接实例化得到。但是所有的对象依赖关系,都用DI容器去管理,这样后面想要更换对象的时候也非常方便,项目...

net core控制器(控制台)中使用依赖注入

net core中使用的依赖注入默认是:DependencyInjection使用nuget下载:install-package Microsoft.Extensions.DependencyIn...

IOC控制反转与DI依赖注入

IOC与DI都是为了降低类与类之间的耦合度。耦合性耦合性也叫块间联系。指软件系统结构中各模块间相互联系紧密程度的一种度量...

IOC 控制反转 Dl 依赖注入

IOC:控制反转DI:注入依赖讲解:类与类之间的耦合性我们之间都是用NEW关键之直接实例化,这样耦合性很高,但是修改很麻烦今...

IOC控制反转和DI依赖注入

IOC控制反转 概念:把类与类的控制器交给容器就是控制反转 使用控制反转一般步骤: (1) 准备一个容器(创建一个类) ...

net core手动获取依赖注入对象

耍朋友的时候要像已经结婚了结了婚要当这婚还没结控制器相关中:HttpContext来获取实例HttpContext下有一个RequestedServic...

.net core 使用依赖注入session

tip:net core 2.2版本后可以直接启用session了,不用在自己添加一次session依赖,本身就添加了的使用工具nuget包管理器 添...

net core创建EF与依赖注入

第一步:创建一个NET Core项目第二步:使用Nuget(程序包管理控制台)添加EF的依赖输入命令: Install-Package Microsoft.En...
这一世以无限游戏为使命!
排名
2
文章
633
粉丝
44
评论
93
docker中Sware集群与service
尘叶心繁 : 想学呀!我教你呀
一个bug让程序员走上法庭 索赔金额达400亿日元
叼着奶瓶逛酒吧 : 所以说做程序员也要懂点法律知识
.net core 塑形资源
剑轩 : 收藏收藏
映射AutoMapper
剑轩 : 好是好,这个对效率影响大不大哇,效率高不高
ASP.NET Core 服务注册生命周期
剑轩 : http://www.tnblog.net/aojiancc2/article/details/167
ICP备案 :渝ICP备18016597号-1
网站信息:2018-2025TNBLOG.NET
技术交流:群号656732739
联系我们:contact@tnblog.net
公网安备:50010702506256
欢迎加群交流技术