IOC

就是我们需要一个对象 以前我们是去 new 现在我们是直接向 IOC容器 要我们需要的那个对象。

使用一个IOC容器(autofac)通过依赖注入控制各个组件的耦合。也就是说你写好了组件,不需要你去自己控制他们的依赖关系,哪个类又持有哪个类的对象,哪个类里面又要声明一个对象,而是把他们都放到一个容器里面,容器替你做这个(把组件组合起来)。

那么IoC是如何做的呢?有点像通过婚介找女朋友,在我和女朋友之间引入了一个第三者:婚姻介绍所。婚介管理了很多男男女女的资料,我可以向婚介提出一个列表,告诉它我想找个什么样的女朋友,比如长得像李嘉欣,身材像林熙雷,唱歌像周杰伦,速度像卡洛斯,技术像齐达内之类的,然后婚介就会按照我们的要求,提供一个mm,我们只需要去和她谈恋爱、结婚就行了。简单明了,如果婚介给我们的人选不符合要求,我们就会抛出异常。整个过程不再由我自己控制,而是有婚介这样一个类似容器的机构来控制。

DI

由容器动态的将某个依赖关系注入到组件之中 就是 一个对象a 需要去访问数据库 以前我们是自己编写代码去创建一个connction对象 来连接对象,现在我们只需要用@autowrite来获取connection对象,在系统运行时,IOC容器会在合适的时候去创建这个对象,对象a不必关心connection是怎么创建的,何时创建的,这就完成了对各个对象关系的控制

理解DI的关键是:“谁依赖谁,为什么需要依赖,谁注入谁,注入了什么”,那我们来深入分析一下:

谁依赖于谁:当然是 应用程序依赖于IoC容器

为什么需要依赖:应用程序需要IoC容器来提供对象需要的外部资源

谁注入谁:很明显是 IoC容器注入应用程序某个对象,应用程序依赖的对象

注入了什么:就是注入某个对象所需要的外部资源(包括对象、资源、常量数据)

Net Core 三个常用的生命周期

首先,我们想象一个这样一个场景。假设我们有寄快递的需求,那么我们会致电快递公司:“我们要寄快递,派一个快递员过来收货”。接着,快递公司会如何做呢?

  1. 一直派遣同一个快递员来收货。
  2. 第一周派遣快递员A、第二周派遣快递员B收货。
  3. 每次都派遣一个新的快递员收货。

1.Transient(瞬态模式):每一次GetService都会创建一个新的实例   瞬间生命周期 : 每次需要创建一个全新的 每次请求时都会创建的瞬时生命周期服务。这个生命周期最适合轻量级,无状态的服

2.Scoped(作用域模式):在同一个Scope内只初始化一个实例 ,可以理解为( 每一个request级别只创建一个实例,同一个http request会在一个 scope内) 单例进程唯一实例 :每一次请求都是同一个(多用于时间) 在同作用域,服务每个请求只创建一次。

3.Singleton(单例模式):整个应用程序生命周期内只创建一个实例   全局只创建一次,第一次被请求的时候被创建,然后就一直使用这一个.

如何使用这三种生命周期呢?.我们直接在注入的时候用不同的方法就行了,代码如下:

  1. //注册不同生命周期的服务
    services.AddTransient<ITestService, TestService>();
  2. services.AddScoped<ITestService2, TestService2>();
  3. services.AddSingleton<ITestService3, TestService3>();  

自带的IOC 做一些小的项目完全没有问题,但是大项目使用起来就比较单一

IOC容器替换为Autofac

AutoFac生命周期

InstancePerLifetimeScope:作用域模式  在一个嵌套语句块中,只会返回一个实例。 在解决每个生命周期实例作用域组件时,每个嵌套作用域将获得一个实例(例如,每个工作单元)。相当于AddScope

SingleInstance:单例模式,每次调用,都会使用同一个实例化的对象;每次都用同一个对象;相当于AddSingleton

InstancePerDependency:瞬态模式  默认模式,每次调用,都会重新实例化对象;每次请求都创建一个新的对象;AddTransient

Autofac可完美替换系统的依赖注入功能,可实现构造函数注入和属性注入,替换过程:

在Program.cs 新增一行代码

  1. public static IHostBuilder CreateHostBuilder(string[] args) =>
  2. Host.CreateDefaultBuilder(args)
  3. .UseServiceProviderFactory(new AutofacServiceProviderFactory())//集成Autofac
  4. .ConfigureWebHostDefaults(webBuilder =>
  5. {
  6. webBuilder.UseStartup<Startup>();
  7. });

然后在Startup.cs 增加方法

  1. //集成Autofac
  2. public void ConfigureContainer(ContainerBuilder builder)
  3. {
  4. //添加依赖注入实例,AutofacModuleRegister就继承自Autofac.Module的类
  5. builder.RegisterModule(new StartupHelp.AutofacModuleRegister());
  6. }

ConfigureAutofac 是自己封装的一个类  继承了 Autofac.Module

其中注册类必须继承自Autofac.Module,并且在Load中实现注入,此处应用了程序集范围的注入以及单个对象的注入,最后添加的代码是为了支持控制器的属性注入。

注入的接口(如IUnitOfWork)和实现(UnitOfWork)没有特别。

注入对象的生命周期与.netcore内置的一致

  1. public class AutofacRegister : Autofac.Module
  2. {
  3. #region 单个类和接口
  4. //直接注册某一个类和接口
  5. //左边的是实现类,右边的As是接口
  6. //containerBuilder.RegisterType<TestServiceE>().As<ITestServiceE>().SingleInstance();
  7. //这里就跟默认DI差不多
  8. //services.AddScoped<TestServiceE, ITestServiceE>();
  9. #endregion
  10.  
  11. #region 方法1 Load 适用于无接口注入
  12. //var assemblysServices = Assembly.Load("Exercise.Services");
  13.  
  14. //containerBuilder.RegisterAssemblyTypes(assemblysServices)
  15. // .AsImplementedInterfaces()
  16. // .InstancePerLifetimeScope();
  17.  
  18. //var assemblysRepository = Assembly.Load("Exercise.Repository");
  19.  
  20. //containerBuilder.RegisterAssemblyTypes(assemblysRepository)
  21. // .AsImplementedInterfaces()
  22. // .InstancePerLifetimeScope();
  23.  
  24. #endregion
  25.  
  26. #region 方法2 选择性注入 与方法1 一样
  27. // Assembly Repository = Assembly.Load("Exercise.Repository");
  28. // Assembly IRepository = Assembly.Load("Exercise.IRepository");
  29. // containerBuilder.RegisterAssemblyTypes(Repository, IRepository)
  30. //.Where(t => t.Name.EndsWith("Repository"))
  31. //.AsImplementedInterfaces().PropertiesAutowired();
  32.  
  33. // Assembly service = Assembly.Load("Exercise.Services");
  34. // Assembly Iservice = Assembly.Load("Exercise.IServices");
  35. // containerBuilder.RegisterAssemblyTypes(service, Iservice)
  36. //.Where(t => t.Name.EndsWith("Service"))
  37. //.AsImplementedInterfaces().PropertiesAutowired();
  38. #endregion
  39.  
  40. #region 方法3 使用 LoadFile 加载服务层的程序集 将程序集生成到bin目录 实现解耦 不需要引用
  41. //获取项目路径
  42. //var basePath = Microsoft.DotNet.PlatformAbstractions.ApplicationEnvironment.ApplicationBasePath;
  43. //var ServicesDllFile = Path.Combine(basePath, "Exercise.Services.dll");//获取注入项目绝对路径
  44. //var assemblysServices = Assembly.LoadFile(ServicesDllFile);//直接采用加载文件的方法
  45. //containerBuilder.RegisterAssemblyTypes(assemblysServices).AsImplementedInterfaces();
  46.  
  47. //var RepositoryDllFile = Path.Combine(basePath, "Exercise.Repository.dll");
  48. //var RepositoryServices = Assembly.LoadFile(RepositoryDllFile);//直接采用加载文件的方法
  49. //containerBuilder.RegisterAssemblyTypes(RepositoryServices).AsImplementedInterfaces();
  50. #endregion
  51.  
  52. #region 在控制器中使用属性依赖注入,其中注入属性必须标注为public
  53. //public ITestServiceE _testService {get;set }
  54. //注意 上方为属性注入 发现为Null 需要在Startup.cs 的 ConfigureServices 方法下加入如下代码
  55. //services.AddControllers().AddControllersAsServices();
  56.  
  57. //在控制器中使用属性依赖注入,其中注入属性必须标注为public
  58. // var controllersTypesInAssembly = typeof(Startup).Assembly.GetExportedTypes()
  59. //.Where(type => typeof(Microsoft.AspNetCore.Mvc.ControllerBase).IsAssignableFrom(type)).ToArray();
  60. // containerBuilder.RegisterTypes(controllersTypesInAssembly).PropertiesAutowired();
  61. #endregion
  62.  
  63. /// <summary>
  64. /// 当前使用
  65. /// </summary>
  66. /// <param name="builder"></param>
  67. protected override void Load(ContainerBuilder builder)
  68. {
  69. //程序集范围注入 将匹配所有Service结尾的
  70. builder.RegisterAssemblyTypes(typeof(SysUserService).Assembly)
  71. .Where(t => t.Name.EndsWith("Service"))
  72. .AsImplementedInterfaces().PropertiesAutowired();
  73. //单个注册 工作单元 和数据库上下文
  74. builder.RegisterType<UnitOfWork>().As<IUnitOfWork>().PropertiesAutowired();
  75. builder.RegisterType<dbContext>().As<DbContext>().PropertiesAutowired();
  76.  
  77. //在控制器中使用属性依赖注入,其中注入属性必须标注为public 就是不需要通过构造函数 直接
  78. //public ITestServiceE _testService {get;set } 可直接_testService.方法 不许在构造函数接收
  79. //注意属性注入 发现为Null 需要在Startup.cs 的 ConfigureServices 方法下加入如下代码
  80. //services.AddControllers().AddControllersAsServices();
  81. var controllersTypesInAssembly = typeof(Startup).Assembly.GetExportedTypes()
  82. .Where(type => typeof(Microsoft.AspNetCore.Mvc.ControllerBase).IsAssignableFrom(type)).ToArray();
  83. builder.RegisterTypes(controllersTypesInAssembly).PropertiesAutowired();
  84. }
  85. }

然后控制器通过构造函数注入,或者属性注入测试

ASP.NET Core 3.1 IOC容器以及默认DI以及替换Autofac生命周期的更多相关文章

  1. Asp.Net Core 内置IOC容器的理解

    Asp.Net Core 内置IOC容器的理解 01.使用IOC容器的好处 对接口和实现类由原来的零散式管理,到现在的集中式管理. 对类和接口之间的关系,有多种注入模式(构造函数注入.属性注入等). ...

  2. [ASP.NET Core 3框架揭秘] 依赖注入[8]:服务实例的生命周期

    生命周期决定了IServiceProvider对象采用怎样的方式提供和释放服务实例.虽然不同版本的依赖注入框架针对服务实例的生命周期管理采用了不同的实现,但总的来说原理还是类似的.在我们提供的依赖注入 ...

  3. 简单讲解Asp.Net Core自带IOC容器ServiceCollection

    一.  理解ServiceCollection之前先要熟悉几个概念:DIP.IOC.DI.Ioc容器: 二.  接下来先简单说一下几个概念问题: 1.DIP(依赖倒置原则):六大设计原则里面一种设计原 ...

  4. [IoC容器Unity]第二回:Lifetime Managers生命周期

    1.引言 Unity的生命周期是注册的类型对象的生命周期,而Unity默认情况下会自动帮我们维护好这些对象的生命周期,我们也可以显示配置对象的生命周期,Unity将按照配置自动管理,非常方便,下面就介 ...

  5. [转载][IoC容器Unity]第二回:Lifetime Managers生命周期

    1.引言 Unity的生命周期是注册的类型对象的生命周期,而Unity默认情况下会自动帮我们维护好这些对象的生命周期,我们也可以显示配置对象的生命周期,Unity将按照配置自动管理,非常方便,下面就介 ...

  6. ASP.NET Core中使用IOC三部曲(一.使用ASP.NET Core自带的IOC容器)

    前言 本文主要是详解一下在ASP.NET Core中,自带的IOC容器相关的使用方式和注入类型的生命周期. 这里就不详细的赘述IOC是什么 以及DI是什么了.. emm..不懂的可以自行百度. 目录 ...

  7. ASP.NET Core中使用IOC三部曲(二.采用Autofac来替换IOC容器,并实现属性注入)

    前言 本文主要是详解一下在ASP.NET Core中,自带的IOC容器相关的使用方式和注入类型的生命周期. 这里就不详细的赘述IOC是什么 以及DI是什么了.. emm..不懂的可以自行百度. 目录 ...

  8. ASP.NET Core中使用IOC三部曲(三.采用替换后的Autofac来实现AOP拦截)

    前言 本文主要是详解一下在ASP.NET Core中,采用替换后的Autofac来实现AOP拦截 觉得有帮助的朋友~可以左上角点个关注,右下角点个推荐 这里就不详细的赘述IOC是什么 以及DI是什么了 ...

  9. .net core系列之《.net core内置IOC容器ServiceCollection》

    一.IOC介绍 IOC:全名(Inversion of Control)-控制反转 IOC意味着我们将对象的创建控制权交给了外部容器,我们不管它是如何创建的,我们只需要知道,当我们想要某个实例时,我们 ...

随机推荐

  1. [CF1454] Codeforces Round #686 (Div. 3) solution

    标签(空格分隔): 经验 题解 时量 : 2h 概括 : \[\text{2min t1 }\\ \text{10min t2 (hacked)}\\ \text{30min t3 }\\ \text ...

  2. Tarjan 算法总结

    一些概念 连通:无向图中的任意两点都可以互相到达. 强连通:有向图中的任意两点都可以互相到达. 连通分量:无向图的极大连通子图. 强连通分量:有向图的极大强连通子图. DFS 生成树:对一张图(有向无 ...

  3. schema设计陷阱

    1.太多的列: mysql的存储引擎api工作时需要在服务器层和存储引擎层之间通过行缓冲格式拷贝数据,然后在服务器层将缓冲内容解码成各个列.从行缓冲中将编码过的列转换成行数据结构的操作代价是非常高的. ...

  4. 微前端大赏二-singlespa实践

    微前端大赏二-singlespa实践 微前端大赏二-singlespa实践 序 介绍singleSpa singleSpa核心逻辑 搭建环境 vue main react child 生命周期 结论 ...

  5. CentOS下关于集群同步/LB/HA 的尝试

    Zookepper 集群同步 下载解压 wget http://apache.fayea.com/zookeeper/stable/zookeeper-3.4.8.tar.gz tar xvf zoo ...

  6. Android动画系列之属性动画

    原文首发于微信公众号:jzman-blog,欢迎关注交流! 属性动画相较帧动画和补间动画更强大,帧动画和补间动画只能应用于 View 及其子类,而属性动画可以修改任何对象的属性值,属性值可在指定的一段 ...

  7. C语言项目——工程化编程的案例分析

    一.VSCode安装及环境配置 初始在Win下安装Mingw-w64/GCC 和 GDB,在VSCode下打开项目案例,发现在linktable中需要包含pthread头文件.此文件是基于Linux系 ...

  8. C++编程指南续(4-5)

    五.常量 常量是一种标识符,它的值在运行期间恒定不变.C语言用 #define来定义常量(称为宏常量).C++ 语言除了 #define外还可以用const来定义常量(称为const常量). 5.1  ...

  9. 第7章 Python类型、类、协议 第7.1节 面向对象程序设计的相关知识

    Python被视为一种面向对象的语言,在介绍Python类相关的内容前,本节对面向对象程序设计相关的概念进行简单介绍. 一.    类和对象(实例) 在面向对象的程序设计(OOP)过程中有两个重要概念 ...

  10. PyQt(Python+Qt)学习随笔:使用实例方法赋值方式捕获事件

    专栏:Python基础教程目录 专栏:使用PyQt开发图形界面Python应用 专栏:PyQt入门学习 老猿Python博文目录 老猿学5G博文目录 在<第15.17节 PyQt(Python+ ...