- 文档
- 教程
- 知识库
【免费下载链接】developer-roadmap
Interactive roadmaps, guides and other educational content to help developers grow in their careers.
导读
依赖注入容器(DI Container)是 ASP.NET Core 应用中管理对象创建与生命周期的核心组件,也是依赖注入(Dependency Injection)模式落地的基础设施。本文围绕 roadmaps/aspnet-core/content/di-containers@iM760f8Ys66-VSkMiZfIX.md 的核心定义展开,结合 ASP.NET Core 内置容器、服务生命周期机制以及 Autofac、Scrutor 等常用第三方容器,带你理解容器如何作为"中央注册表"自动解析并注入依赖,掌握AddTransient/AddScoped/AddSingleton三种注册方式的实际用法与选型原则,从而写出低耦合、易测试、可维护的 ASP.NET Core 应用。
什么是 DI 容器
DI 容器是一个框架组件,负责管理应用中对象的实例化(instantiation)与生命周期(lifetime)。它扮演"中央注册表(central registry)"的角色:你在这里声明"哪个具体实现要提供给哪个接口或基类"。
当应用请求某个服务时,容器会自动完成以下工作:
- 解析依赖:根据注册信息找到目标接口对应的具体实现类型;
- 注入依赖:把解析出来的实例通过构造函数(或属性)注入到请求方类中;
- 管理释放:按照注册时声明的服务生命周期,在合适的时机调用
IDisposable.Dispose()释放对象。
正是因为这层"注册—解析—注入"的机制,组件之间才得以解耦:类不再需要亲自new出自己依赖的对象,而是只声明"我需要什么",由容器决定"从哪来、何时创建、何时销毁"。
该主题在 ASP.NET Core 技术路线中处于核心位置,与 依赖注入模式、服务生命周期 等知识点紧密关联,也是框架基础能力(ASP.NET Core 基础)中明确列出的核心特性之一。
ASP.NET Core 的内置 DI 容器
ASP.NET Core 把依赖注入直接内建在框架之中,不需要额外安装任何包即可使用。其底层实现是Microsoft.Extensions.DependencyInjection库——一个轻量级容器,负责在应用内创建和管理对象的生命周期。
集中注册:IServiceCollection
容器的一切注册都发生在一个集中的地方:IServiceCollection。最典型的注册入口是Program.cs中的builder.Services:
var builder = WebApplication.CreateBuilder(args); builder.Services.AddScoped<IOrderRepository, OrderRepository>(); builder.Services.AddSingleton<ICacheService, RedisCacheService>(); builder.Services.AddTransient<IEmailSender, SmtpEmailSender>(); var app = builder.Build();注册完成后,容器会在应用启动时构建出真实的IServiceProvider,后续所有组件的构造请求都由它统一响应。这正是 DI 容器"中央注册表"定位的最直观体现:你在一个位置声明全部依赖关系,剩下的解析与注入交给容器。
注入方式:构造函数注入
ASP.NET Core 默认推荐、也最常用的是构造函数注入。控制器、中间件、服务类都可以直接在构造函数中声明所需依赖,由容器自动提供:
public class OrderController : ControllerBase { private readonly IOrderRepository _repository; private readonly IEmailSender _emailSender; public OrderController( IOrderRepository repository, IEmailSender emailSender) { _repository = repository; _emailSender = emailSender; } }生命周期:容器如何决定实例的去留
容器管理对象生命周期的方式,是 DI 容器区别于"简单工厂"的关键。ASP.NET Core 提供三种主要生命周期(详见 服务生命周期文档):
| 生命周期 | 创建时机 | 共享范围 | 适用场景 |
|---|---|---|---|
| Transient | 每次请求服务时都创建新实例 | 不共享 | 轻量、无状态服务 |
| Scoped | 每个客户端请求(HTTP 请求)内创建一次 | 同一请求内共享 | 一个用户交互内需要保持一致状态的服务(如DbContext) |
| Singleton | 首次被请求时创建(或应用启动时) | 整个应用生命周期共享 | 共享状态、配置、缓存等 |
Transient:每次都要"新"的
Transient 生命周期 规定:每次从容器请求服务时都生成一个全新实例,即使同一个请求内多次注入也各不相同。它非常适合轻量、无状态的服务,因为对象不跨组件共享,天然避免了共享状态带来的并发问题:
builder.Services.AddTransient<INotificationSender, NotificationSender>();Scoped:一个请求一个实例
Scoped 生命周期 规定:每个 HTTP 请求内只创建一个实例,处理该请求的所有组件共享同一个实例。这让单个用户交互的全过程数据保持一致,同时又不会把状态泄漏到其他无关请求中。EF Core 的DbContext默认就是 Scoped,这是它能在一次请求内安全共享、跨请求各自独立的原因:
builder.Services.AddScoped<IMyDbContext, MyDbContext>();Singleton:全程只有一个
Singleton 生命周期 规定:实例在首次被请求(或应用启动)时创建一次,之后整个应用生命周期内所有请求都复用同一个实例。它适合保存共享状态、全局配置或缓存数据的服务:
builder.Services.AddSingleton<IAppCache, AppCache>();生命周期选型与常见陷阱
- Singleton 的线程安全要求:单例实例被所有请求并发访问,内部状态必须线程安全;
- 避免"捕获依赖"(Captive Dependency):不要把一个 Scoped 服务注入到 Singleton 服务中——Singleton 只创建一次,被捕获的 Scoped 实例实际上会退化为 Singleton 语义,引发状态串扰;正确做法是让 Singleton 通过
IServiceScopeFactory按需创建作用域; - Transient 的轻量原则:如果服务创建成本高(如持有大量资源),Transient 频繁创建会带来性能开销,此时应考虑 Scoped 或 Singleton;
- Dispose 时机:容器会跟踪它自己创建的实现了
IDisposable的实例,并在作用域结束或应用关闭时统一释放。注意:容器不会释放由你自己new出来再注册进容器的对象,这类对象由调用方自行负责清理。
第三方容器:当内置容器不够用时
内置容器(Microsoft.Extensions.DependencyInjection)满足绝大多数场景,但当应用需要更复杂的生命周期管理、程序集扫描或 AOP 式装饰时,可以引入第三方容器(详见 Microsoft.Extensions.DependencyInjection 文档)。
Autofac:成熟的 IoC 容器
Autofac 是 .NET 生态中最流行的 IoC 容器之一,核心能力包括:
- 在构造函数、属性上自动解析并注入所需服务;
- 支持复杂的对象生命周期配置(如每依赖、每作用域、每匹配等);
- 支持程序集扫描批量注册;
- 通过模块(Module)机制组织大型应用的依赖配置。
典型的接入方式是在Program.cs中用builder.Host.UseServiceProviderFactory替换默认容器工厂,并在ConfigureContainer中编写 Autofac 注册:
var builder = WebApplication.CreateBuilder(args); builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory()); builder.Host.ConfigureContainer<ContainerBuilder>(containerBuilder => { containerBuilder.RegisterType<OrderService>() .As<IOrderService>() .InstancePerLifetimeScope(); });Scrutor:给内置容器加装配扫描与装饰
Scrutor 不是替代容器,而是对内置容器的增强扩展,主要带来两个能力:
- 程序集扫描注册:按约定或特性自动注册服务,减少手写注册的样板代码:
builder.Services.Scan(scan => scan .FromAssemblyOf<Program>() .AddClasses(classes => classes.AssignableTo<IOrderRepository>()) .AsImplementedInterfaces() .WithScopedLifetime());- 装饰器(Decorator)支持:用干净利落的语法为既有服务叠加横切关注点(如日志、缓存),而无需修改原始实现类:
builder.Services.AddTransient<IOrderService, OrderService>(); builder.Services.Decorate<IOrderService, LoggingOrderService>();这与 MediatR 通过 pipeline 添加日志、校验、异常处理等行为的思路异曲同工——都是用"不侵入原始实现"的方式扩展行为。
小结
DI 容器是 ASP.NET Core 依赖注入体系的执行引擎,它通过集中注册、自动解析、按生命周期注入与释放,把组件间的耦合降到最低。掌握内置容器的三种生命周期(Transient / Scoped / Singleton)是日常开发的必备技能;当应用复杂度上升时,Autofac 提供更强生命周期控制与模块化组织,Scrutor 则以内置容器为基础补充装配扫描与装饰能力。配合本仓库 ASP.NET Core 路线图,可以继续深入学习 依赖注入模式 与 服务生命周期 的更多细节。
- 文档
- 教程
- 知识库
【免费下载链接】developer-roadmap
Interactive roadmaps, guides and other educational content to help developers grow in their careers.
相关推荐
探索ASP.NET Dependency Injection:轻量级、强大的服务容器
探索ASP.NET Dependency Injection:轻量级、强大的服务容器 是一个由微软开发并开源的框架,它为ASP.NET Core应用程序提供了依
三步上手 Cherry Studio:多模型聚合与 300+ 预置助手的 AI 桌面客户端完整指南
三步上手 Cherry Studio:多模型聚合与 300+ 预置助手的 AI 桌面客户端完整指南 Cherry Studio 是一个支持 Windows、ma
AI 应用大模型桌面应用本地部署RAGTypeGraphQL 依赖注入(Dependency Injection)实战指南:接入 TypeDI、InversifyJS 与请求级作用域容器
TypeGraphQL 依赖注入(Dependency Injection)实战指南:接入 TypeDI、InversifyJS 与请求级作用域容器 TypeG
后端GraphQLAPI设计
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考