.NETEasy
AddSingleton vs AddScoped vs AddTransient — when to use which?
AddTransient — a new instance every time it's resolved:
services.AddTransient<IGuidGenerator, GuidGenerator>();
Use for stateless services that are cheap to create.
AddScoped — one instance per HTTP request:
services.AddScoped<IUnitOfWork, EfUnitOfWork>();
Use for anything that holds per-request state (DbContext, current-user context).
AddSingleton — one instance for the entire app lifetime:
services.AddSingleton<IMemoryCache, MemoryCache>();
services.AddSingleton<IHttpClientFactory, ...>();
Use for thread-safe utilities, caches, and configuration.
The lifetime trap:
services.AddSingleton<EmailService>();
public class EmailService(AppDbContext db) { /* ... */ } // ❌
A singleton holding a scoped DbContext leaks: the context outlives the request, the connection never returns to the pool, and you'll see ObjectDisposedException randomly.
Rule: the dependency's lifetime must be ≥ the dependent's lifetime. Singleton can only depend on Singleton.