17370845950

C# 依赖注入方法 C#在ASP.NET Core中如何实现依赖注入
ASP.NET Core 6+ 在 Program.cs 中通过 builder.Services 注册服务,推荐使用 AddSingleton、AddScoped(多数业务首选)、AddTransient;构造函数须为 public;多实现需用 IEnumerable 注入;IDbConnection 应工厂创建,HttpClient 须用 AddHttpClient;自定义服务依赖应通过工厂委托从 IServiceProvider 获取。

ASP.NET Core 的 Program.cs 中如何注册服务

ASP.NET Core 6+ 默认使用精简的 Program.cs 模式,服务注册直接在 var builder = WebApplication.CreateBuilder(args) 后调用 builder.Services。这是唯一推荐的入口点,别在 Startup.cs(已

弃用)或中间件里注册。

常见注册方式有三类,区别在于生命周期管理:

  • AddSingleton():整个应用生命周期共用一个实例,适合无状态工具类、配置读取器
  • AddScoped():每个 HTTP 请求创建一次,跨中间件/控制器复用,**绝大多数业务服务应选这个**
  • AddTransient():每次注入都新建实例,适合轻量、无共享状态的类(如 DTO 映射器)

示例:

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddSingleton(builder.Configuration);
builder.Services.AddScoped();
builder.Services.AddTransient();

构造函数注入是否必须 public?能否注入多个同类型服务

构造函数必须是 public,否则运行时抛出 InvalidOperationException: Unable to resolve service。.NET DI 容器只识别 public 构造函数。

同一接口注册多个实现时,默认只取最后一个——除非你明确使用集合注册:

  • AddScoped() 多次注册 → 只生效最后一次
  • 改用 AddScoped() + AddScoped() → 仍只取最后注册的
  • 正确做法:builder.Services.AddScoped(); builder.Services.AddScoped();,然后在构造函数中接收 IEnumerable

这样容器会自动聚合所有已注册的 IMessageHandler 实现。

DI 容器无法解析 IDbConnectionHttpClient 怎么办

这些类型不能直接注册为单例或作用域服务,原因不同:

  • IDbConnection:是“即用即开即关”的资源,注册为 Scoped 会导致连接被跨请求复用,引发 InvalidOperation: Connection is already in use。应改为工厂模式或在 Repository 内部用 new SqlConnection(...) 创建
  • HttpClient:官方强烈建议用 AddHttpClient() 注册,而不是 AddScoped()。后者易导致端口耗尽(socket exhaustion),因为 HttpClient 本身是线程安全且设计为长期复用的,但底层 HttpMessageHandler 需要按需管理生命周期

正确写法:

builder.Services.AddHttpClient()
    .ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler
    {
        ServerCertificateCustomValidationCallback = (msg, cert, chain, err) => true
    });

自定义服务需要访问 IConfigurationIWebHostEnvironment 怎么办

不要在构造函数里试图“手动 new 自定义服务”,这会绕过 DI 容器,导致依赖链断裂。正确方式是让容器帮你传参:

  • 在注册时用工厂委托:AddScoped(sp => new RedisCacheService(sp.GetRequiredService()))
  • 工厂内可安全调用 sp.GetRequiredService<...>() 获取其他已注册服务
  • 注意:工厂委托中不能捕获外部变量(如局部 config 变量),必须从 IServiceProvider 获取,否则可能拿到错误作用域的实例

特别提醒:IConfigurationIWebHostEnvironment 是 Singleton,可放心在任何生命周期的服务中注入;但反过来,Scoped 服务不能注入到 Singleton 类的构造函数中,否则启动时报错。