Cannot resolve scoped service from root provider .Net Core 2

后端 未结 4 677
心在旅途
心在旅途 2020-12-07 19:45

When I try to run my app I get the error

InvalidOperationException: Cannot resolve \'API.Domain.Data.Repositories.IEmailRepository\' from root provider beca         


        
相关标签:
4条回答
  • 2020-12-07 20:12

    Middleware is always a singleton so you can't have scoped dependencies as constructor dependencies in the constructor of your middleware.

    Middleware supports method injection on the Invoke method,so you can just add the IEmailRepository emailRepository as a parameter to that method and it will be injected there and will be fine as scoped.

    public async Task Invoke(HttpContext context, IEmailRepository emailRepository)
    {
    
        ....
    }
    
    0 讨论(0)
  • 2020-12-07 20:15

    You registered the IEmailRepository as a scoped service, in the Startup class. This means that you can not inject it as a constructor parameter in Middleware because only Singleton services can be resolved by constructor injection in Middleware. You should move the dependency to the Invoke method like this:

    public ExceptionHandlingMiddleware(RequestDelegate next)
    {
        _next = next;
    }
    
    public async Task Invoke(HttpContext context, IEmailRepository emailRepository)
    {
        try
        {
            await _next.Invoke(context);
        }
        catch (Exception ex)
        {
            await HandleExceptionAsync(context, ex, emailRepository);
        }
    }
    
    0 讨论(0)
  • 2020-12-07 20:20

    Your middleware and the service has to be compatible with each other in order to inject the service via the constructor of your middleware. Here, your middleware has been created as a convention-based middleware which means it acts as a singleton service and you have created your service as scoped-service. So, you cannot inject a scoped-service into the constructor of a singleton-service because it forces the scoped-service to act as a singleton one. However, here are your options.

    1. Inject your service as a parameter to the InvokeAsync method.
    2. Make your service a singleton one, if possible.
    3. Transform your middleware to a factory-based one.

    A Factory-based middleware is able to act as a scoped-service. So, you can inject another scoped-service via the constructor of that middleware. Below, I have shown you how to create a factory-based middleware.

    This is only for demonstration. So, I have removed all the other code.

    public class Startup
    {
        public Startup()
        {
        }
    
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddScoped<TestMiddleware>();
            services.AddScoped<TestService>();
        }
    
        public void Configure(IApplicationBuilder app)
        {
            app.UseMiddleware<TestMiddleware>();
        }
    }
    

    The TestMiddleware:

    public class TestMiddleware : IMiddleware
    {
        public TestMiddleware(TestService testService)
        {
        }
    
        public Task InvokeAsync(HttpContext context, RequestDelegate next)
        {
            return next.Invoke(context);
        }
    }
    

    The TestService:

    public class TestService
    {
    }
    
    0 讨论(0)
  • 2020-12-07 20:29

    Another way to get the instance of scoped dependency is to inject service provider (IServiceProvider) into the middleware constructor, create scope in Invoke method and then get the required service from the scope:

    using (var scope = _serviceProvider.CreateScope()) {
        var _emailRepository = scope.ServiceProvider.GetRequiredService<IEmailRepository>();
    
        //do your stuff....
    }
    

    Check out Resolving Services in a Method Body in asp.net core dependency injection best practices tips tricks for more details.

    0 讨论(0)
提交回复
热议问题