Reputation: 23
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
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