C# 依赖注入方法 C#在ASP.NET Core中如何实现依赖注入

来源:这里教程网 时间:2026-02-21 17:39:55 作者:

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

ASP.NET Core 6+ 默认使用精简的

Program.cs
模式,服务注册直接在
var builder = WebApplication.CreateBuilder(args)
后调用
builder.Services
。这是唯一推荐的入口点,别在
Startup.cs
(已弃用)或中间件里注册。

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

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

示例:

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddSingleton<IConfiguration>(builder.Configuration);
builder.Services.AddScoped<IOrderService, OrderService>();
builder.Services.AddTransient<IEmailSender, SmtpEmailSender>();

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

构造函数必须是

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

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

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

这样容器会自动聚合所有已注册的

IMessageHandler
实现。

DI 容器无法解析
IDbConnection
HttpClient
怎么办

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

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

正确写法:

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

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

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

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

特别提醒:

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

相关推荐