nemanja o
nemanja o

Reputation: 23

.NET Core Dependency Injection error having generic service and repository code

I am trying to move the generic code template I was using in .NET framework in all my projects to .NET Core, and I am having some troubles with dependency injection in .NET core.

Here is my code:

API Controller:

[Route("api/[controller]")]
[ApiController]
public class ProductController : ControllerBase
{
    private readonly IProductService _productService;

    public ProductController(IProductService productService)
    {
        _productService = productService;
    }

    [HttpGet]
    public IActionResult GetAll()
    {
        var products = _productService.GetAll();

        return Ok(products);
    }
}

ProductService:

public class ProductService : ServiceBase<Product, BaseRepository<Product>>, IProductService
{
    public ProductService(BaseRepository<Product> rep) : base(rep)
    {
    }
}

IProductService:

public interface IProductService : IServiceBase<Product>
{
}

IServiceBase:

public interface IServiceBase<TEntity>
{
    IEnumerable<TEntity> GetAll();
}

ServiceBase:

public abstract class ServiceBase<TEntity, TRepository> : IServiceBase<TEntity>
        where TEntity : class
        where TRepository : BaseRepository<TEntity>
{
    public TRepository Repository;

    public ServiceBase(BaseRepository<TEntity> rep)
    {
        Repository = (TRepository)rep;
    }

    public IEnumerable<TEntity> GetAll()
    {
        return Repository.GetAll();
    }
}

BaseRepository:

public class BaseRepository<T> : IBaseRepository<T> where T : class
{
    private readonly DatabaseContext _dbContext;

    public BaseRepository(DatabaseContext dbContext)
    {
        _dbContext = dbContext;
    }

    public IEnumerable<T> GetAll()
    {
        return _dbContext.Set<T>();
    }
}

IBaseRepository:

public interface IBaseRepository<T> where T : class
{
    IEnumerable<T> GetAll();
}

DatabaseContext:

public class DatabaseContext : DbContext
{
    public DatabaseContext(DbContextOptions<DatabaseContext> options) : base(options)
    {
    }

    public DbSet<Product> Products { get; set; }
}

Startup file:

public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddDbContext<DatabaseContext>(options =>
            options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"),
            x => x.MigrationsAssembly("AdministrationPortal.Data")));

        services.AddTransient<IProductService, ProductService>();

        services.AddControllers();
    }

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }

        app.UseHttpsRedirection();

        app.UseRouting();

        app.UseAuthorization();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllers();
        });
    }
}

The error I get when I try to start API project using F5 (or green play button):

System.AggregateException: 'Some services are not able to be constructed (Error while validating the service descriptor 'ServiceType: AdministrationPortal.Interfaces.Services.IProductService Lifetime: Transient ImplementationType: AdministrationPortal.Core.Services.ProductService': Unable to resolve service for type 'AdministrationPortal.Repositories.Repositories.BaseRepository`1[AdministrationPortal.Domain.Entities.Product]' while attempting to activate 'AdministrationPortal.Core.Services.ProductService'.)'

Any help is appreciated!

Upvotes: 2

Views: 522

Answers (1)

devNull
devNull

Reputation: 4219

Your ProductService class is trying to resolve a dependency for BaseRepository<Product>, but you haven't registered that in the service provider. In your Startup class, you can simply register that type and it should work:

public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContext<DatabaseContext>(options =>
        options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"),
        x => x.MigrationsAssembly("AdministrationPortal.Data")));

    services.AddTransient<IProductService, ProductService>();
    services.AddTransient<BaseRepository<Product>>(); // <----- This is needed

    services.AddControllers();
}

Alternatively, you can register the BaseRepository<> as an open generic and it will be resolved using any type that it's given:

services.AddTransient(typeof(BaseRepository<>));

Upvotes: 3

Related Questions