0Pricing
C# Academy · 课时

服务生命周期:Transient、Scoped、Singleton

了解 Transient、Scoped 和 Singleton 生命周期如何影响对象的创建、共享与释放。

服务生命周期:Transient、Scoped、Singleton 是 CoddyKit 上的免费 C# Academy 课时。 这是第 2 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 C# Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 C# Academy 课程共包含 4 节课。

生命周期为何重要

服务生命周期决定实例存活多长时间以及创建多少个实例。选择错误的生命周期会导致隐蔽的错误,例如请求之间的数据泄露或对象创建过多。

瞬时:每次创建新的实例

瞬时服务每次从容器请求时都会重新创建。对于轻量级、无状态的服务,可以使用这种生命周期;在这类服务中共享状态可能会带来风险。

builder.Services.AddTransient<IEmailSender, SmtpEmailSender>();

// Each resolution creates a new instance:
// var a = sp.GetRequiredService<IEmailSender>(); // new
// var b = sp.GetRequiredService<IEmailSender>(); // new (different)

作用域:每个请求一次

作用域服务在每个作用域内创建一次——在 ASP.NET Core 中通常对应一个 HTTP 请求。同一个实例会在一次请求中共享,但下一个请求会创建新的实例。

builder.Services.AddScoped<AppDbContext>();

// Within a single HTTP request:
// Both resolve to the SAME AppDbContext instance
// -> consistent unit of work across the request

单例:贯穿应用程序生命周期的一个实例

单例服务只创建一次,并在整个应用程序生命周期内重复使用。对于创建成本高且线程安全的服务(例如配置缓存),可以使用这种生命周期。

builder.Services.AddSingleton<IMemoryCache, MemoryCache>();

// Or register a pre-built instance:
var config = new AppConfig { MaxRetries = 3 };
builder.Services.AddSingleton<IAppConfig>(config);

三种生命周期对比

下面进行快速并列比较:

  • 瞬时——每次请求创建新实例;适用于无状态工具
  • 作用域——每个 HTTP 请求一个实例;适用于 DbContext、工作单元
  • 单例——整个应用程序生命周期内一个实例;适用于缓存、配置

被捕获依赖项问题

将作用域或瞬时服务注入单例是常见错误。单例会持有对短生命周期服务的引用,使其存活时间过长。

// BAD: Singleton captures a Scoped service
public class MySingleton
{
    private readonly AppDbContext _db; // Scoped!
    public MySingleton(AppDbContext db) => _db = db;
    // _db is now stuck alive for the app's lifetime
}

检测作用域违规

启用 ValidateScopes,这样当检测到被捕获的依赖项时,容器会在启动时抛出错误。这可以在错误导致生产环境数据问题之前将其发现。

builder.Host.UseDefaultServiceProvider(options =>
{
    options.ValidateScopes = true;   // detect captive deps
    options.ValidateOnBuild = true;  // fail fast at start
});

请求之外的作用域服务

要在后台任务中解析作用域服务,请使用 IServiceScopeFactory 创建显式作用域。切勿直接从根容器解析作用域服务。

public class MyWorker : BackgroundService
{
    private readonly IServiceScopeFactory _factory;

    public MyWorker(IServiceScopeFactory factory) => _factory = factory;

    protected override async Task ExecuteAsync(CancellationToken ct)
    {
        using var scope = _factory.CreateScope();
        var db = scope.ServiceProvider.GetRequiredService<AppDbContext>();
        await db.Users.ToListAsync(ct);
    }
}

瞬时可释放服务

从根容器解析的瞬时 IDisposable 服务会一直被跟踪,直到容器释放(应用程序关闭)。请在作用域内解析它们,以便及时释放资源。

// Correctly scoped transient disposable
using var scope = sp.CreateScope();
var svc = scope.ServiceProvider.GetRequiredService<MyDisposableService>();
await svc.DoWorkAsync();
// svc.Dispose() called when scope is disposed

选择合适的生命周期

一个简单的判断指南:

  • 服务是否无状态?→ 瞬时
  • 服务是否依赖请求(例如用户身份、DbContext)?→ 作用域
  • 服务是否线程安全且创建成本高?→ 单例

实际应用:同时使用三种生命周期

典型的 Web API 会为不同的服务注册合适的生命周期,以确保正确性和性能。

builder.Services.AddSingleton<IConfiguration>(builder.Configuration);
builder.Services.AddSingleton<ICacheService, RedisCacheService>();

builder.Services.AddScoped<AppDbContext>();
builder.Services.AddScoped<IOrderRepository, OrderRepository>();
builder.Services.AddScoped<OrderService>();

builder.Services.AddTransient<IEmailSender, SendGridEmailSender>();

快速检查

当单例服务持有对作用域服务的引用时,会出现什么问题?

回顾:服务生命周期

要点总结:

  • 瞬时:每次创建新实例——适用于无状态、轻量级服务
  • 作用域:每个请求一个实例——适用于 DbContext、存储库、工作单元
  • 单例:始终只有一个实例——适用于缓存、配置、线程安全工具
  • 切勿将短生命周期服务注入较长生命周期的服务(被捕获的依赖项)
  • 使用 IServiceScopeFactory 在后台任务中解析作用域服务

常见问题解答

「服务生命周期:Transient、Scoped、Singleton」课时是免费的吗?

是的 — 「服务生命周期:Transient、Scoped、Singleton」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 C# Academy 课程的其余内容,请升级到 CoddyKit PRO。 C# Academy 课程共包含 4 节课。

「服务生命周期:Transient、Scoped、Singleton」这节课中我会学到什么?

了解 Transient、Scoped 和 Singleton 生命周期如何影响对象的创建、共享与释放。 你通过在浏览器中直接运行的动手代码来练习 C# Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 C# Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 C# Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 2 节课,共 4 节。

「服务生命周期:Transient、Scoped、Singleton」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 C# Academy 课中编写并运行代码吗?

能。每节 C# Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. DI 容器基础
  2. 服务生命周期:Transient、Scoped、Singleton
  3. 构造函数注入与接口
  4. 工厂与选项模式
← 返回 C# Academy