You need to enable JavaScript to run this app. AddSingleton、AddScoped与AddTransient的适用场景及实际案例说明
优惠活动
大模型
产品
解决方案
定价
更多

AddSingleton、AddScoped与AddTransient的适用场景及实际案例说明

.NET 依赖注入三种服务注册方式的适用场景与真实案例

首先明确三种注册方式的核心生命周期差异:

  • AddTransient:每次从DI容器请求服务时,都会创建全新的实例
  • AddScoped:同一个作用域(ASP.NET Core中默认对应单个HTTP请求)内仅创建一个实例,不同作用域的实例互相隔离
  • AddSingleton:整个应用运行生命周期内仅创建一个实例,所有请求共享该实例

1. AddTransient

适用场景

无状态、轻量化、不需要跨调用共享状态的服务,创建销毁成本极低,每次使用后即可被回收。

真实应用案例:密码哈希工具类

这类服务只负责纯计算逻辑,没有任何需要保存的全局状态,每次调用的输出仅和输入参数有关,完全不需要复用实例。

代码示例

服务定义:

public interface IPasswordHasher
{
    string Hash(string rawPassword);
    bool Verify(string rawPassword, string hashedPassword);
}

public class BcryptPasswordHasher : IPasswordHasher
{
    // 无全局字段,所有逻辑都在方法内实现,完全无状态
    public string Hash(string rawPassword) => BCrypt.Net.BCrypt.HashPassword(rawPassword, workFactor: 11);
    public bool Verify(string rawPassword, string hashedPassword) => BCrypt.Net.BCrypt.Verify(rawPassword, hashedPassword);
}

注册代码:
builder.Services.AddTransient<IPasswordHasher, BcryptPasswordHasher>();

注意:不要在单例服务中直接注入Transient服务,否则Transient实例会被单例持有,生命周期被拉长为单例,不符合预期


2. AddScoped

适用场景

需要在单个请求/作用域内共享状态,作用域结束后即可释放的服务,适合和单次请求绑定的上下文类、资源类服务。

真实应用案例1:EF Core 数据库上下文(DbContext)

EF Core的DbContext默认就是推荐注册为Scoped,同一个请求内的所有数据库操作共用同一个DbContext,可以保证事务一致性,避免多上下文带来的并发脏写问题,请求结束后自动释放上下文占用的数据库连接资源。

注册代码

builder.Services.AddScoped<AppDbContext>();
比如用户提交订单的接口中,先查询用户余额、再扣减余额、最后生成订单,三个操作在同一个请求内共用同一个DbContext,保证操作的原子性,不会出现查询和扣减用不同上下文导致的超扣问题。

真实应用案例2:当前请求用户上下文服务

很多业务场景下需要在控制器、领域服务、仓储层多个位置获取当前登录的用户信息,就可以定义一个Scoped的用户上下文服务,在请求的中间件阶段赋值,整个请求内的所有服务都可以共享同一个用户信息,不同请求之间互相隔离。

代码示例

服务定义:

public interface ICurrentUser
{
    int UserId { get; set; }
    string UserName { get; set; }
}

public class CurrentUser : ICurrentUser
{
    public int UserId { get; set; }
    public string UserName { get; set; }
}

注册代码:
builder.Services.AddScoped<ICurrentUser, CurrentUser>();


3. AddSingleton

适用场景

需要全局共享状态、初始化成本高、本身线程安全的服务,整个应用运行期间只需要初始化一次即可。

真实应用案例1:全局站点配置服务

站点的基础配置一般存在appsettings.json中,只需要在应用启动时读取一次即可,不需要每次用都重新读配置文件,适合注册为单例。

代码示例

配置类定义:

public class SiteConfig
{
    public string SiteName { get; set; }
    public int MaxUploadFileSizeMb { get; set; }
    public string CustomerServiceEmail { get; set; }
}

注册代码:
builder.Services.AddSingleton(builder.Configuration.GetSection("SiteConfig").Get<SiteConfig>());

真实应用案例2:全局内存缓存服务

ASP.NET Core自带的IMemoryCache默认就是单例注册,所有请求共享同一个缓存池,才能实现缓存的复用效果,如果注册为Scoped或者Transient,每个请求单独维护缓存,就完全失去了缓存的意义。

注意:单例服务是多线程共享的,所有操作必须保证线程安全,避免出现并发问题;如果需要在单例服务中使用Scoped服务,必须手动创建作用域获取,不能直接注入


内容的提问来源于stack exchange,提问作者Dev Sharma

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.15 01:24:02