Search code examples
entity-frameworkasp.net-coreasp.net-web-apidependency-injectionef-core-8.0

How to insert a C# interface to a service class in DI container


I'm confused on how to pass on dependencies that come from the DI Container onto a constructor of a class.

I've got the following registrations:

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers();
    services.AddDbContext<StockManagerContext>(o =>
        o.UseSqlServer(Configuration.GetConnectionString("connectionString")));
    services.AddTransient<ITxnNoGenerationRepository, TxnNoGenerationService>();
    services.AddScoped<IResultRepository, ResultService>();
    services.AddTransient<ICustomerRepository>(c => #<-- Compile error here
        new CustomerService(
            c.GetRequiredService<StockManagerContext>(),
            new TxnNoGenerationService(
                c.GetRequiredService<StockManagerContext>())),
            new ResultService());
}

But I'm getting a compile on the marked line above. The C# compiler complains:

There is no argument given that corresponds to the required parameter 'resultrepository' of CustomerService.CustomerService(StockManagerContex,ITxnNoGenerationRepository,IResultRepository)"

This are my interface definitions:

public interface ICustomerRepository
{
    Task<Result> Get();
    Task<Result> Post(CustomerDetail customerDetail);
}

public interface IResultRepository
{
    Result ReturnSuccessResult();
    Result ReturnErrorResult();
}

public interface ITxnNoGenerationRepository
{
    Task<NextNo> TxnNoGeneration(string code);
}

And this is my service class that seems to cause the compile error:

public class CustomerService : ICustomerRepository
{
    private readonly StockManagerContext _context;
    private readonly ITxnNoGenerationRepository _txnNoGenerationRepositiory;
    private readonly IResultRepository _resultRepository;

    public CustomerService(
        StockManagerContext context,
        ITxnNoGenerationRepository txnNoGenerationRepository,
        IResultRepository resultRepository)
    {
        _context = context;
        _resultRepository = _resultRepository;
        _txnNoGenerationRepositiory = txnNoGenerationRepository;
    }

    public async Task<Result> Get() ...

    public async Task<Result> Post(CustomerDetail customerDetail) ...
}

How can I pass these dependancies in Startup.cs class?


Solution

  • The compile error is caused by misplacement of a bracket. This is the code you have (indenting mine):

    services.AddTransient<ICustomerRepository>(c =>
        new CustomerService(
            c.GetRequiredService<StockManagerContext>(),
            new TxnNoGenerationService(
                c.GetRequiredService<StockManagerContext>())),
        new ResultService());
    

    With this indenting you can more easily see the issue. One bracket should be moved to let the code become this:

    services.AddTransient<ICustomerRepository>(c =>
        new CustomerService(
            c.GetRequiredService<StockManagerContext>(),
            new TxnNoGenerationService(
                c.GetRequiredService<StockManagerContext>()),
            new ResultService()));
    

    You are, however, using the lambda/factory syntax to register CustomerService. You should prefer the simpler Auto-Wiring syntax:

    services.AddTransient<ICustomerRepository, CustomerService>();
    

    With this registration, the DI Container will find the dependencies on your behalf and will inject them automatically into CustomerService's constructor. This leads to more maintainable code.