Lesson 16 / 26

Service Lifetimes

Choose between transient, scoped and singleton and avoid the captive dependency bug.

Three lifetimes

Transient: a new instance every time. Scoped: one instance per HTTP request. Singleton: one instance for the whole app. Database contexts are scoped; stateless helpers and caches are often singletons.

Registering each lifetime

Pick the shortest lifetime that works. A singleton must be thread-safe because many requests share it.

builder.Services.AddTransient<IIdGenerator, IdGenerator>();
builder.Services.AddScoped<IOrderService, OrderService>();
builder.Services.AddSingleton<IClock, SystemClock>();

Captive dependency

A singleton must not hold a scoped service such as DbContext: it would keep one request's instance alive forever. In development, scope validation catches this at startup.

Quick check: How many instances of a scoped service exist during one HTTP request?

  • A new one per use
  • Zero
  • One
  • One per thread forever
Answer

One — Scoped services are created once per request scope and shared within it.