How to inject an IServiceScope into a class in .NET Core

Viewed 3351

I have a problem with injecting Microsoft.Extensions.DependencyInjection.IServiceScope into my class.

My service implementation:

public class AccountService : IAccountService
{
    private readonly IConfiguration _configuration;
    private readonly IServiceScope _services;

    public AccountService(
        IConfiguration configuration,
        IServiceScope services) // <-- I can't inject this
    {
        _configuration = configuration;
        _services = services;
    }
    
    public async Task CreateAccount(ExternalAccount externalAccount)
    {
        (some code...)
    }
}

In startup.cs:

services.AddTransient<IAccountService, AccountService>();

The problem is that project crashes after above line with following error:

Some services are not able to be constructed (Error while validating the service descriptor 'ServiceType: IDS.Quickstart.Account.IAccountService Lifetime: Transient ImplementationType: IDS.Quickstart.Account.AccountService': Unable to resolve service for type 'Microsoft.Extensions.DependencyInjection.IServiceScope' while attempting to activate 'IDS.Quickstart.Account.AccountService'.) ---> System.InvalidOperationException: Error while validating the service descriptor 'ServiceType: IDS.Quickstart.Account.IAccountService Lifetime: Transient ImplementationType: IDS.Quickstart.Account.AccountService': Unable to resolve service for type 'Microsoft.Extensions.DependencyInjection.IServiceScope' while attempting to activate 'IDS.Quickstart.Account.AccountService'.

What is the reason my code refuses to work?

1 Answers

Instead of injecting an IServiceScope, with MS.DI you inject an IServiceProvider. MS.DI will automatically inject a version of the IServiceProvider that is scoped to the current scope. This means that your class can call IServiceProvider.GetService which will lead to the same results as what would happen when you call IServiceScope.ServiceProvider.GetService.

Please be careful with the injection of container-specific abstractions such as IServiceProvider, IServiceScopeFactory, or IServiceScope. If injected into classes that live outside your Composition Root, it leads to the Service Locator anti-pattern. Service Locator comes with quite a few downsides. The name of your class, AccountService, makes me believe that this class lives outside your Composition Root.

Classes that live inside the Composition Root typically consist of solely infrastructure logic (no business logic). Within the Composition Root it is fine to have a dependency on the DI Container (or its abstractions) because this part of the already has a very strong dependency on that particular DI Container.

So if you can, extract the logic that requires to resolve instances from the AccountService class, and move that into a class that consists of solely infrastructure logic, and place it inside the Composition Root.

Related