What lifetime should you register a repository, a service, and a cache?
Quick Answer
Repository / unit-of-work / anything touching DbContext → Scoped (matches the request-scoped context). Stateless domain/application services → Scoped by default (or Transient if truly stateless and cheap). Cache, clock, configuration, HttpClient factory internals → Singleton (thread-safe, app-wide).
Anything that touches the DbContext — repositories, the unit of work — is scoped, because the context itself is scoped per request and everything in that request should share it. My stateless application services I also register as scoped by default; transient is only for genuinely trivial stateless helpers. Singletons are for things that are shared across the whole app and are safe to share: a memory cache, a clock, configuration. And the rule that a singleton can only inject other singletons always applies.
- Scoped is the safe default in a web app — it lines up with the request and with EF Core.
- Transient is fine for lightweight stateless helpers; avoid it for anything holding a connection or that's expensive to build.
- Singleton for shared state that's safe to share — but it must be thread-safe and it can only depend on other singletons.
- An in-memory cache is a singleton; a per-request cache of computed values is scoped.