Search code examples
c#asp.net-coredependency-injection.net-coreasp.net-core-2.2

Getting IConfiguration in own ServiceCollection


Im making fixture to my tests.

In my FixtureFactory im making my own ServiceCollection:

    private static ServiceCollection CreateServiceCollection()
    {
        var services = new ServiceCollection();

        services.AddScoped<IConfiguration>();
        services.AddScoped<ITokenService, TokenService>();
        services.AddDbContext<TaskManagerDbContext>(o => o.UseInMemoryDatabase(Guid.NewGuid().ToString()));
        services.AddIdentity<ApplicationUser, IdentityRole>(options =>
        {
            options.Password.RequiredLength = 6;
            options.Password.RequireLowercase = false;
            options.Password.RequireUppercase = false;
            options.Password.RequireNonAlphanumeric = false;
            options.Password.RequireDigit = false;
            options.User.RequireUniqueEmail = true;
        }).AddEntityFrameworkStores<TaskManagerDbContext>();

        return services;
    }

Then, im getting this services from scope:

    var services = CreateServiceCollection().BuildServiceProvider().CreateScope();

    var context = services.ServiceProvider.GetRequiredService<TaskManagerDbContext>();
    var userManager = services.ServiceProvider.GetRequiredService<UserManager<ApplicationUser>>();
    var roleManager = services.ServiceProvider.GetRequiredService<RoleManager<IdentityRole>>();
    var signInManager = services.ServiceProvider.GetRequiredService<SignInManager<ApplicationUser>>();
    var tokenService = services.ServiceProvider.GetRequiredService<TokenService>();

The problem starts when i added TokenService to my ServiceCollection.

Constructor, of TokenService looks like this:

    private readonly IConfiguration configuration;

    private readonly UserManager<ApplicationUser> userManager;

    public TokenService(IConfiguration configuration, UserManager<ApplicationUser> userManager)
    {
        this.configuration = configuration;
        this.userManager = userManager;
    }

It works great when i launch my Core app, but wont work from ServiceCollection that i mentioned above.

In Tests, i started to get this error:

Message: System.AggregateException : One or more errors occurred. (Cannot instantiate implementation type 'Microsoft.Extensions.Configuration.IConfiguration' for service type 'Microsoft.Extensions.Configuration.IConfiguration'.) (The following constructor parameters did not have matching fixture data: ServicesFixture fixture) ---- System.ArgumentException : Cannot instantiate implementation type 'Microsoft.Extensions.Configuration.IConfiguration' for service type 'Microsoft.Extensions.Configuration.IConfiguration'. ---- The following constructor parameters did not have matching fixture data: ServicesFixture fixture

This error started to show when i added services.AddScoped<IConfiguration>(); to my ServiceCollection and when i started to get required service TokenService.

My question is, how to register properly Configuration that im using in Service?

Im using Configuration to get items from settings.json.

EDIT:

My fixture and sample test class:

public class ServicesFixture
{
    public TaskManagerDbContext Context { get; private set; }

    public UserManager<ApplicationUser> UserManager { get; private set; }

    public RoleManager<IdentityRole> RoleManager { get; private set; }

    public SignInManager<ApplicationUser> SignInManager { get; private set; }

    public TokenService TokenService { get; private set; }

    public ServicesFixture()
    {
        var servicesModel = ServicesFactory.CreateProperServices();

        this.Context = servicesModel.Context;
        this.UserManager = servicesModel.UserManager;
        this.RoleManager = servicesModel.RoleManager;
        this.SignInManager = servicesModel.SignInManager;
        this.TokenService = servicesModel.TokenService;
    }

    [CollectionDefinition("ServicesTestCollection")]
    public class QueryCollection : ICollectionFixture<ServicesFixture>
    {
    }
}

Tests:

[Collection("ServicesTestCollection")]
public class CreateProjectCommandTests
{
    private readonly TaskManagerDbContext context;

    public CreateProjectCommandTests(ServicesFixture fixture)
    {
        this.context = fixture.Context;
    }
}

EDIT2

When i delete AddScoped<IConfiguration>(); from my collection and run tests, i get this error:

Message: System.AggregateException : One or more errors occurred. (No service for type 'TaskManager.Infrastructure.Implementations.TokenService' has been registered.) (The following constructor parameters did not have matching fixture data: ServicesFixture fixture) ---- System.InvalidOperationException : No service for type 'TaskManager.Infrastructure.Implementations.TokenService' has been registered. ---- The following constructor parameters did not have matching fixture data: ServicesFixture fixture


Solution

  • You added IConfiguration with no implementation.

    In startup.cs the framework would have created an implementation behind the scenes and added it. You will have to do the same using ConfigurationBuilder

    var builder = new ConfigurationBuilder()
        //.SetBasePath("path here") //<--You would need to set the path
        .AddJsonFile("appsettings.json"); //or what ever file you have the settings
    
    IConfiguration configuration = builder.Build();
    
    services.AddScoped<IConfiguration>(_ => configuration);
    
    //...