1 · Structure and rendering · 30 MIN
Dependency injection and service lifetimes
A service lifetime determines who shares an instance.
The dependency-injection container supplies registered services to endpoint parameters. This clock is stateless and safe to share as a singleton. A scoped database context normally belongs to a request scope; injecting it into a singleton incorrectly extends its lifetime and can create unsafe concurrent access. Transient services create new instances on resolution. Choose lifetime from ownership and thread-safety requirements instead of treating singleton as a free optimization.
Verify the endpoint has no direct new SystemClock call.
Read the example
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddSingleton<IClock, SystemClock>();
var app = builder.Build();
app.MapGet("/time", (IClock clock) => new {utc=clock.UtcNow});
app.Run();
public interface IClock { DateTimeOffset UtcNow {get;} }
public sealed class SystemClock : IClock { public DateTimeOffset UtcNow => DateTimeOffset.UtcNow; }Check the expected output
GET /time returns a UTC timestamp supplied through IClock.
Your challenge
Replace IClock with a fixed implementation in a test and explain why an EF DbContext should not be held by this singleton.
Solution cost: O(1) clock access. time · One shared stateless clock service. space
Common trap
A singleton containing per-user mutable fields can mix data between requests.
Study the project implementation
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddSingleton<IClock, SystemClock>();
var app = builder.Build();
app.MapGet("/time", (IClock clock) => new {utc=clock.UtcNow});
app.Run();
public interface IClock { DateTimeOffset UtcNow {get;} }
public sealed class SystemClock : IClock { public DateTimeOffset UtcNow => DateTimeOffset.UtcNow; }Further reading: Official documentation
Next lesson: DTO validation at an API boundary →