Service Lifetimes: Transient vs Scoped vs Singleton
1Concept
`Transient` creates a new instance on every injection. `Scoped` creates one instance per HTTP request scope. `Singleton` creates a single shared instance across the entire application process lifetime.
2Architecture Diagram
HTTP Request 1 ──> [ Scoped Service A (Instance 1) ] ──> Disposed on Request End HTTP Request 2 ──> [ Scoped Service A (Instance 2) ] ──> Disposed on Request End Both Requests ──> [ Singleton Service B (Shared Instance 1) ] ──> Lives forever
3Code Example
C# 13 & .NET 9
using System;
using Microsoft.Extensions.DependencyInjection;
public interface IOperation { Guid Id { get; } }
public class TransientOp : IOperation { public Guid Id { get; } = Guid.NewGuid(); }
public class SingletonOp : IOperation { public Guid Id { get; } = Guid.NewGuid(); }
public class DiLifetimesDemo
{
public static void Main()
{
var services = new ServiceCollection();
services.AddTransient<TransientOp>();
services.AddSingleton<SingletonOp>();
var provider = services.BuildServiceProvider();
Console.WriteLine($"Transient 1: {provider.GetRequiredService<TransientOp>().Id}");
Console.WriteLine($"Transient 2: {provider.GetRequiredService<TransientOp>().Id} (Different!)");
Console.WriteLine($"Singleton 1: {provider.GetRequiredService<SingletonOp>().Id}");
Console.WriteLine($"Singleton 2: {provider.GetRequiredService<SingletonOp>().Id} (Identical!)");
}
}4Expected Output
Transient 1: d3b07384-d113-4a3e-b83b-9a8c16027a01 Transient 2: 7f8a91c2-3e4b-4a5c-9d6e-8b1a2c3d4e5f (Different!) Singleton 1: a1b2c3d4-e5f6-4a5b-8c9d-0e1f2a3b4c5d Singleton 2: a1b2c3d4-e5f6-4a5b-8c9d-0e1f2a3b4c5d (Identical!)
5Key Takeaways
- ✓Entity Framework DbContext must always be registered as `Scoped`.
- ✓Singletons must be 100% thread-safe.
- ✓Transient services should be lightweight without holding unmanaged resources.