文章首发地址c#
在上一篇中,咱们讲述了什么是控制反转(IoC)以及经过哪些方式实现的。这其中,咱们明白了,控制反转(IoC) 是一种软件设计的模式,指导咱们设计出更优良,更具备松耦合的程序,而具体的实现方式有依赖注入和依赖查找。框架
在上篇实例中,咱们经过日志的方式举例说明,其中经过代码建立了一个ILogger
的接口,并实现接口实例,基于控制反转的模式,依赖的建立也移交到了外部,可是也发现存在了问题,若是相似存在这样多个接口和实现类,依赖太多,一一建立,没有统一的管理,这反而增长了实际工做量麻烦。ide
所以咱们须要一个能够统一管理系统中全部的依赖的地方,所以,IoC容器诞生了。函数
容器负责两件事情:学习
因此在这一篇中,咱们主要讲述Asp.Net Core中内置的IoC容器。测试
在Asp.Net Core中已经为咱们集成提供了一个内置的IoC容器,咱们能够看到在Startup.cs
的ConfigureServices
中,涉及到依赖注入的核心组件,一个负责实例注册的IServiceCollection
和一个负责提供实例的IServiceProvider
ui
简单的说就是两步:1. 把实例注册到容器中;2. 从容器中获取实例.net
而在这其中,IServiceCollection
为实现将开发者定义好的实例注册进去提供了三种方法。设计
分别是:日志
AddTransient 、AddScoped 、AddSingleton
而这三种不一样实例方法也对应的着三种不一样的实例生命周期。
三种不一样的生命周期:
AddTransient
每次在向服务容器进行请求时都会建立新的实例,这种生存期适合轻量级、 无状态的服务。
AddScoped
在每次Web请求时被建立一次实例,生命周期横贯整次请求。
局部单例对象, 在某个局部内是同一个对象(做用域单例,本质是容器单例);一次请求内是一个单例对象,屡次请求则多个不一样的单例对象。
AddSingleton
建立单例生命周期服务的状况以下:
其后的每个后续请求都使用同一个实例。若是开发者的应用须要单例服务情景,推荐的作法是交给服务容器来负责单例的建立和生命周期管理,而不是手动实现单例模式而后由开发者在自定义类中进行操做。
不要从单一实例解析指定了做用域的服务。 当处理后续请求时,它可能会致使服务处于不正确的状态。 能够从范围内或暂时性服务解析单一实例服务。
定义三个接口,分别测试Singleton,Scope,Transient三种,一个 TestService服务
public interface ITransientService { string GetGuid(); }
public interface IScopedService { string GetGuid(); }
public interface ISingletonService { string GetGuid(); }
public interface ITestService { public string GetSingletonID(); public string GetTransientID(); public string GetScopedID(); }
根据上面定义的几种接口,并一一实现对应的接口
public class TransientService : ITransientService { public string OperationId { get; } public TransientService() { OperationId = Guid.NewGuid().ToString()[^4..]; } public string GetGuid() { return $"这是一个 Transient service : " + OperationId; } }
public class ScopedService : IScopedService { public string OperationId { get; } public ScopedService() { OperationId = Guid.NewGuid().ToString()[^4..]; } public string GetGuid() { return $"这是一个 scoped service : "+ OperationId; } }
public class SingletonService : ISingletonService { public string OperationId { get; } public SingletonService() { OperationId = Guid.NewGuid().ToString()[^4..]; } public string GetGuid() { return $"这是一个 Singleton service : " + OperationId; } }
public class TestService : ITestService { private ITransientService _transientService; private IScopedService _scopedService; private ISingletonService _singletonService; public TestService(ITransientService transientService, IScopedService scopedService, ISingletonService singletonService) { _transientService = transientService; _scopedService = scopedService; _singletonService = singletonService; } public string GetSingletonID() { return _singletonService.GetGuid(); } public string GetTransientID() { return _transientService.GetGuid(); } public string GetScopedID() { return _scopedService.GetGuid(); } }
在Startup.cs
类文件ConfigureServices
方法中,注入依赖
public void ConfigureServices(IServiceCollection services) { services.AddControllers(); services.AddTransient<ITransientService, TransientService>(); services.AddSingleton<ISingletonService, SingletonService>(); services.AddScoped<IScopedService, ScopedService>(); services.AddScoped<ITestService, TestService>(); }
定义一个控制器,实现调用
[ApiController] [Route("[controller]")] public class TestController : ControllerBase { private ITransientService _transientService; private IScopedService _scopedService; private ISingletonService _singletonService; private ITestService _testService; public TestController(ITransientService transientService, IScopedService scopedService, ISingletonService singletonService, ITestService testService ) { _transientService = transientService; _scopedService = scopedService; _singletonService = singletonService; _testService = testService; } [HttpGet] public JsonResult Get() { var data1 = _transientService.GetGuid(); var data2 = _testService.GetTransientID(); var data3 = _scopedService.GetGuid(); var data4 = _testService.GetScopedID(); var data5 = _singletonService.GetGuid(); var data6 = _testService.GetSingletonID(); return new JsonResult(new { data1, data2, data3 , data4, data5, data6, }); } }
在上面中咱们了解到,注入的方式通常有三种,构造函数注入, 方法注入,属性注入,而在ASP.NET Core中自带的这个IoC容器,默认采用了构造函数注入的方式。
启动运行项目,访问接口/Test
效果以下:
对比两次的请求访问能够发现,上面咱们一共获得了 4个Transient实例,2个Scope实例,1个Singleton实例。
在请求中,AddSingleton方式的id值相同;
AddScope方式两次请求之间不一样,但同一请求内是相同的;
AddTransient方式在同一请求内的屡次注入间都不相同。
经过上述的代码示例,也证明了以前的三种方式对应不一样生命周期的说明。
暂时性(Transient) : 生命周期是每次得到对象都是一次新的对象,每一次都不同。
做用域内(Scoped) : 生命周期是在每一次请求做用域内是同一个对象,非做用域内则是新的对象。
单例(Singletion) : 生命周期是这个服务启动后都是一个对象,也便是全局单例对象
。
经过上述的了解,咱们知道IoC容器是一个依赖注入框架,在.NET Core中也提供了内置的IoC容器,经过AddXXX方法来实例依赖对象,而在实际开发中,就是每个实例都须要一个个的添加,这样的实现方式在小项目中还好,可是若是在复杂大型的项目中,就略向麻烦些,可能须要添加不少方法来实现,总体的可观性也很差。
为了达到能够简化咱们工做量,应该采用批量注册,所以咱们也能够引入其余的Ioc容器框架,实现更多的功能和扩展。
在平时开发中,经常使用的IoC框架有不少,而在这里咱们选择用Autofac,这也是在.net下比较流行的,其余的框架不作说明,可自行查阅了解。
ASP.Net Core中使用Autofac 框架注入 (在后续篇章会具体说明)
在实际的开发中,对于这几种生命周期,咱们应该如何应用呢?
好比,在像DBContext这种实例,在实际开发中是用Transient 仍是Scoped呢?
建议使用Scoped
由于有些对象在请求中能够须要用到多个方法或者多个Service、Repository的时候,为了减小实例初始化的消耗,实现事务功能,能够在整个请求的生命周期共用一个Scope。
其余的思考:
以上的思考,你们能够说说本身的想法
在后续的篇章中,也会对这些问题,进行深刻讨论说明。
本篇主要介绍了什么是IoC容器,了解到它是DI构造函注入的框架,它管理着依赖项的生命周期以及映射关系,同时也介绍实践了在ASP.Net Core中,默认提供的内置IoC容器,以及它的实例注册方式和相应的生命周期。
好啦,这篇文章就先讲述到这里吧,在后续篇章中会对ASP.Net Core中使用Autofac 框架实践说明,但愿对你们有所帮助。
若是有不对的或不理解的地方,但愿你们能够多多指正,提出问题,一块儿讨论,不断学习,共同进步。🤣