5

I was reading the MS doc about DI in .Net Core.

https://learn.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-2.2

I came across the line

"Warning

When using a scoped service in a middleware, inject the service into the Invoke or InvokeAsync method. Don't inject via constructor injection because it forces the service to behave like a singleton."

Anyone, please explain what is the meaning of this?

Then one of the most voted answer here uses constructor DI injection for scoped service. AddTransient, AddScoped and AddSingleton Services Differences?

vinayak hegde
  • 2,117
  • 26
  • 26

2 Answers2

5

This is documented in ASP.NET Core Middleware: Per-request dependencies.

Because middleware is constructed at app startup, not per-request, scoped lifetime services used by middleware constructors aren't shared with other dependency-injected types during each request. If you must share a scoped service between your middleware and other types, add these services to the Invoke method's signature. The Invoke method can accept additional parameters that are populated by DI:

public class CustomMiddleware
{
private readonly RequestDelegate _next;

public CustomMiddleware(RequestDelegate next)
{
    _next = next;
}

// IMyScopedService is injected into Invoke
public async Task Invoke(HttpContext httpContext, IMyScopedService svc)
{
    svc.MyProperty = 1000;
    await _next(httpContext);
}
}
Ryan
  • 19,118
  • 10
  • 37
  • 53
3

This is quite an important thing. Your middleware class is instantiated only once, i.e. its constructor only runs once. If you have a dependency with lifetime of scoped or transient, it is meant to be shorter-lived. If you require such a dependency via the constructor, your middleware is dependent on a service with a shorter lifetime. The DI container can dispose the service after a request is done, leaving your middleware with a service which no longer works.

By requesting it at runtime in the Invoke/InvokeAsync function, you are able to use transient and scoped dependencies. Singletons can be required in the constructor, since those have the same lifetime as the middleware.

juunas
  • 54,244
  • 13
  • 113
  • 149
  • I'm not sure this is exact, I believe the DI will not "dispose" the service, but rather remove it's reference and leave the object to be garbage collected. However, garbage collection won't happen because the object is still referenced by your middleware – Tomap Jul 18 '20 at 09:12
  • 1
    The DI containwe will call the service's Dispose function if it implements IDisposable. – juunas Jul 18 '20 at 20:13