Service Lifetimes: Transient, Scoped, Singleton
Learn how Transient, Scoped, and Singleton lifetimes affect object creation, sharing, and disposal.
Service Lifetimes: Transient, Scoped, Singleton is a free C# Academy lesson on CoddyKit — lesson 2 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the C# Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.
Why Lifetimes Matter
Service lifetime controls how long an instance lives and how many instances are created. Picking the wrong lifetime causes subtle bugs like data leaks between requests or excessive object creation.
Transient: New Every Time
Transient services are created fresh every time they are requested from the container. Use them for lightweight, stateless services where sharing state would be dangerous.
builder.Services.AddTransient<IEmailSender, SmtpEmailSender>();
// Each resolution creates a new instance:
// var a = sp.GetRequiredService<IEmailSender>(); // new
// var b = sp.GetRequiredService<IEmailSender>(); // new (different)Scoped: Once Per Request
Scoped services are created once per scope — typically one HTTP request in ASP.NET Core. The same instance is shared within a request but a new one is created for the next request.
builder.Services.AddScoped<AppDbContext>();
// Within a single HTTP request:
// Both resolve to the SAME AppDbContext instance
// -> consistent unit of work across the requestSingleton: One for the App Lifetime
Singleton services are created once and reused for the entire application lifetime. Use them for expensive-to-create, thread-safe services like configuration caches.
builder.Services.AddSingleton<IMemoryCache, MemoryCache>();
// Or register a pre-built instance:
var config = new AppConfig { MaxRetries = 3 };
builder.Services.AddSingleton<IAppConfig>(config);Comparing All Three
A quick side-by-side comparison:
- Transient — new instance every request; stateless utilities
- Scoped — one per HTTP request; DbContext, Unit of Work
- Singleton — one for app lifetime; caches, configs
The Captive Dependency Problem
Injecting a Scoped or Transient service into a Singleton is a common mistake. The Singleton holds a reference to the short-lived service, keeping it alive too long.
// 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
}Detecting Scope Violations
Enable ValidateScopes so the container throws at startup if a captive dependency is detected. This catches mistakes before they cause production data bugs.
builder.Host.UseDefaultServiceProvider(options =>
{
options.ValidateScopes = true; // detect captive deps
options.ValidateOnBuild = true; // fail fast at start
});Scoped Services Outside a Request
To resolve Scoped services in a background task, create an explicit scope using IServiceScopeFactory. Never resolve Scoped services directly from the root container.
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);
}
}Transient Disposable Services
Transient IDisposable services resolved from the root container are tracked until the container is disposed (app shutdown). Resolve them inside a scope to release resources promptly.
// Correctly scoped transient disposable
using var scope = sp.CreateScope();
var svc = scope.ServiceProvider.GetRequiredService<MyDisposableService>();
await svc.DoWorkAsync();
// svc.Dispose() called when scope is disposedChoosing the Right Lifetime
A simple decision guide:
- Is the service stateless? → Transient
- Does it depend on a request (e.g., user identity, DbContext)? → Scoped
- Is it thread-safe and expensive to build? → Singleton
Real-World: Three Lifetimes Together
A typical web API registers different services with appropriate lifetimes for correctness and performance.
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>();Quick Check
What problem occurs when a Singleton service holds a reference to a Scoped service?
Recap: Service Lifetimes
Key takeaways:
- Transient: new instance each time — good for stateless, lightweight services
- Scoped: one instance per request — DbContext, repositories, unit-of-work
- Singleton: one instance forever — caches, configs, thread-safe utilities
- Never inject short-lived services into longer-lived ones (captive dependency)
- Use
IServiceScopeFactoryto resolve Scoped services in background tasks
Frequently asked questions
Is the “Service Lifetimes: Transient, Scoped, Singleton” lesson free?
Yes — the full text of “Service Lifetimes: Transient, Scoped, Singleton” is free to read here on the web, and the C# Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the C# Academy course, upgrade to CoddyKit PRO.
What will I learn in “Service Lifetimes: Transient, Scoped, Singleton”?
Learn how Transient, Scoped, and Singleton lifetimes affect object creation, sharing, and disposal. You practise C# Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.
Do I need any experience to start C# Academy?
No prior experience is required. C# Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 2 of 4, so you can start here or from the beginning and move at your own pace.
How long does the “Service Lifetimes: Transient, Scoped, Singleton” lesson take?
Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.
Can I write and run code in this C# Academy lesson?
Yes. Every C# Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.
All lessons in this course
- DI Container Fundamentals
- Service Lifetimes: Transient, Scoped, Singleton
- Constructor Injection & Interfaces
- Factory & Options Patterns