5:依赖注入:良好架构的起点(上)-.NET Core开发实战
.NET Core开发实战前文传送门:
文章目录
05 | 依赖注入:良好架构的起点
为什么要使用依赖注入框架
- 借助依赖注入框架,我们可以轻松管理类之间的依赖,帮助我们在构建应用时遵循设计原则,确保代码的可维护性和可扩展性
- ASP.NET Core 的整个架构中,依赖注入框架提供了对象创建和生命周期管理的核心能力,各个组件相互协作,也是由依赖注入框架的能力来实现的
组件包
- Microsoft.Extensions.DependencyInjection.Abstractions
- Microsoft.Extensions.DependencyInjection
依赖注入的核心是以上两个组件包,一个是抽象包,一个是具体的实现
这里用到了一个经典的设计模式,接口实现分离模式
组件只需要依赖抽象接口,而不需要依赖具体实现,当使用的时候注入它的具体实现即可
这样做的好处是可以在使用时决定具体的实现,也就意味着未来可以做任意的扩展,替换依赖注入框架的具体实现
默认情况下,使用 .NET Core 提供的内置依赖注入框架,也可以使用第三方的依赖注入框架来替换默认实现
核心类型
- IServiceCollection:服务的注册
- ServiceDescriptor:每一个服务注册时的信息
- IServiceProvider:具体的容器,由 ServiceCollection Build 产生
- IServiceScope:一个容器的子容器的生命周期
生命周期
- 单例 Singleton:在整个根容器的生命周期内,都是单例,不管是子容器还是根容器,与作用域的区别是:一个是全局的,一个是范围的单例
- 作用域 Scoped:在 Scope 的生存周期内,也就是容器的生存周期内,或者子容器的生存周期内,如果我的容器释放掉,我的对象也会释放掉
- 瞬时(暂时)Transient:每一次从容器里面获取对象时,都可以得到一个全新的对象
新建一个 ASP.NET Core Web 应用程序 DependencyInjectionDemo,选择API
添加一个 Services 文件夹,新建三个服务代表三个生命周期的服务
namespace DependencyInjectionDemo.Services { public interface IMyScopedService { } public class MyScopedService : IMyScopedService { } }
namespace DependencyInjectionDemo.Services { public interface IMySingletonService { } public class MySingletonService : IMySingletonService { } }
namespace DependencyInjectionDemo.Services { public interface IMyTransientService { } public class MyTransientService : IMyTransientService { } }
在 Startup 中注册服务
public void ConfigureServices(IServiceCollection services) { #region 注册服务不同生命周期的服务 // 将单例的服务注册为单例的模式 services.AddSingleton<IMySingletonService, MySingletonService>(); // Scoped 的服务注册为 Scoped 的生命周期 services.AddScoped<IMyScopedService, MyScopedService>(); // 瞬时的服务注册为瞬时的生命周期 services.AddTransient<IMyTransientService, MyTransientService>(); #endregion services.AddControllers(); }
在 Controller 里面获取我们的服务
// FromServices 标注的作用是从容器里面获取我们的对象 // 每个对象获取两遍,用于对比每个生命周期获取的对象是什么样子的 // HashCode 代表对象的唯一性 [HttpGet] public int GetService( [FromServices]IMySingletonService singleton1, [FromServices]IMySingletonService singleton2, [FromServices]IMyTransientService transient1, [FromServices]IMyTransientService transient2, [FromServices]IMyScopedService scoped1, [FromServices]IMyScopedService scoped2) { Console.WriteLine($"singleton1:{singleton1.GetHashCode()}"); Console.WriteLine($"singleton2:{singleton2.GetHashCode()}"); Console.WriteLine($"transient1:{transient1.GetHashCode()}"); Console.WriteLine($"transient2:{transient2.GetHashCode()}"); Console.WriteLine($"scoped1:{scoped1.GetHashCode()}"); Console.WriteLine($"scoped2:{scoped2.GetHashCode()}"); Console.WriteLine($"========请求结束========"); return 1; }
启动程序,刷新浏览器再次访问接口,输出如下:

单例模式两次的 HashCode 没有变化
两个瞬时服务两次的 HashCode 完全不同,意味着瞬时服务每次请求都会得到一个新对象
范围服务每个请求内是相同的,不同的请求之间得到的对象实例是不同的。

原文出处:微信公众号【DotNet NB】,作者【郑子铭】
原文链接:https://mp.weixin.qq.com/s/ZrZ-i3OOcOgiUa7xWUdL6w
本文观点不代表Dotnet9立场,转载请联系原作者。