.NET 内置依赖注入容器是 IServiceCollection + IServiceProvider,原生支持、无需额外安装,仅提供构造函数注入和 Transient/Scoped/Singleton 生命周期管理。

什么是 .NET 内置的依赖注入容器
.NET 从 Core 开始就内置了轻量级 DI 容器,类型是 IServiceCollection + IServiceProvider,它不是第三方库(比如 Autofac 或 DryIoc),而是框架原生支持的抽象层。你不需要额外安装包(Microsoft.Extensions.DependencyInjection 在 Microsoft.NET.Sdk 项目中默认引用)。
它的定位是“够用、安全、与 Host 集成好”,不追求高级特性(如属性注入、装饰器、命名注册)。如果你只需要构造函数注入 + 生命周期管理(Transient / Scoped / Singleton),它完全胜任。
如何注册服务并获取实例
注册靠 IServiceCollection 扩展方法,解析靠 IServiceProvider 的 GetService() 或 GetRequiredService() :
-
AddTransient() :每次请求都新建实例
-
AddScoped() :每个作用域(如一次 HTTP 请求)内复用同一个实例
-
AddSingleton() :整个应用生命周期只创建一次
var services = new ServiceCollection();
services.AddTransient();
services.AddScoped();
services.AddSingleton();
var provider = services.BuildServiceProvider();
// 使用
var userService = provider.GetRequiredService();
AddTransient() :每次请求都新建实例AddScoped() :每个作用域(如一次 HTTP 请求)内复用同一个实例AddSingleton() :整个应用生命周期只创建一次var provider = services.BuildServiceProvider();
// 使用
var userService = provider.GetRequiredService
注意:GetService 返回 null 表示未注册;GetRequiredService 抛出 InvalidOperationException(更推荐,避免空引用)。
为什么在 Program.cs 中用 CreateHostBuilder 而不是手动 new ServiceCollection
在 Web 项目(.NET 6+)中,你不该手动构建 IServiceProvider,而应通过 Host.CreateDefaultBuilder() 或 WebApplicationBuilder 注入服务:
var builder = WebApplication.CreateBuilder(args);
// 注册服务(自动使用内置容器)
builder.Services.AddTransient();
builder.Services.AddHttpClient();
var app = builder.Build();
// 注册服务(自动使用内置容器)
builder.Services.AddTransient
var app = builder.Build();
原因:
- 手动
BuildServiceProvider()会提前触发容器构建,导致中间件、配置、日志等尚未注入 - Host 会帮你处理作用域生命周期(比如
HttpContext绑定Scoped服务) - 第三方扩展(如 EF Core、MediatR)依赖 Host 的服务发现机制
容易踩的坑:循环依赖和泛型注册
循环依赖在编译期不报错,运行时首次解析时抛出 InvalidOperationException: A circular dependency was detected。典型场景是 A 依赖 B,B 又依赖 A(包括间接依赖)。
泛型注册要注意闭合类型 vs 开放泛型:
services.AddTransient(typeof(IHandler ✅ 支持开放泛型映射-
services.AddTransient✅ 显式注册闭合类型, OrderCreatedHandler>(); - 但
services.AddTransient❌ 编译失败 —— C# 不允许泛型类型参数在泛型方法调用中作为实参直接出现, Handler >()
复杂对象图或需要 AOP/装饰器时,内置容器能力很快见顶。这时候才该考虑引入 Autofac 并替换默认容器 —— 但先确认是不是真需要,别一上来就上重武器。










