Why can't you inject a scoped service into the constructor of custom middleware?

ASP.NET Core Dependency Injection Advanced 3–5 Yrs5+ Yrs Debugging 1 min read

Quick Answer

Conventional middleware is instantiated once at startup (effectively a singleton), so injecting a scoped service like DbContext into its constructor is a captive dependency. Instead, inject scoped services as parameters of the InvokeAsync(HttpContext, IMyScopedService) method — the framework resolves them from the request scope on each call.

Middleware written the conventional way is created once when the app starts and reused for every request — it's basically a singleton. So if I inject a DbContext into its constructor, that's a captive dependency: one context shared across all requests and threads. The fix is to put the scoped dependencies on the InvokeAsync method signature instead — InvokeAsync(HttpContext ctx, AppDbContext db) — and the framework resolves them from the current request's scope each time. Or I implement IMiddleware and register it as scoped, which is the factory-based model where constructor injection works.

  • Constructor injection in middleware → only singletons (and IHttpContextAccessor, transient factories).
  • Method injection → public async Task InvokeAsync(HttpContext ctx, AppDbContext db) — resolved per request.
  • Alternative: implement IMiddleware and register it as a scoped/transient service (factory-based middleware) — then constructor injection of scoped services works.