Reputation: 9963
I am trying to use autofac with a repository and I am trying to add a little generics to try reducing the amount of duplicate code I am writing.However I am going round in circles trying to get autofac to work for me
So I created a domainservice and interface that handles our the standard crud operations
public class DomainService<T>:IDomainService<T>
{
protected readonly IDomainService<T> Repository;
public DomainService(IDomainService<T> repository)
{
Repository = repository;
}
public IQueryable<T> GetQueryable()
{
return Repository.GetQueryable();
}
public virtual Task<T> Add(T entity)
{
return Repository.Add(entity);
}
Interface:
public interface IDomainService<T>
{
IQueryable<T> GetQueryable();
Task<T> Add(T entity);
Task<bool> Delete(T entity);
Task<T> Update(T entity);
Task<T> GetById(int id);
Task<T> GetByUID(Guid id);
}
I am using my repo is nothing special
public class SkillRepository : DomainService<Skill>, ISkill
{
private DataContext _db = new DataContext();
private readonly ILogger _log = null;
public SkillRepository(IDomainService<Skill> repository, ILogger log) : base(repository)
{
_log = log;
}
}
Finally where I wire up autofac:
var builder = new ContainerBuilder();
// Register the Web API controllers.
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
// Register other dependencies.
builder.Register(c => new Logger()).As<ILogger>().InstancePerApiRequest();
builder.RegisterType<SkillRepository>()
.As<IDomainService<Skill>>()
.As<ISkill>()
.InstancePerRequest();
// Build the container.
var container = builder.Build();
// Create the depenedency resolver.
var resolver = new AutofacWebApiDependencyResolver(container);
// Configure Web API with the dependency resolver.
GlobalConfiguration.Configuration.DependencyResolver = resolver;
My web api controller looks like
public class SkillsController : BaseController<Skill>
{
private readonly ISkill _skillRepository;
public SkillsController(SkillRepository skillRepository) : base(skillRepository)
{
_skillRepository = skillRepository;
}
}
BaseController
public abstract class BaseController<TEntity> : ApiController
where TEntity : new()
{
protected readonly IDomainService<TEntity> DomainService;
protected BaseController(IDomainService<TEntity> domainService)
{
DomainService = domainService;
}
I get an exception:
"None of the constructors found with 'Autofac.Core.Activators.Reflection.DefaultConstructorFinder' on type 'Api.EndPoints.Skills.SkillsController' can be invoked with the available services and parameters:\ \ Cannot resolve parameter 'Domain.Repository.SkillRepository skillRepository' of constructor 'Void .ctor(Domain.Repository.SkillRepository)'."
Is there something obvious that I am doing wrong?
Upvotes: 3
Views: 1890
Reputation: 1442
In my opinion you should first sort out names for your classes which is making it hard to understand the code itself. secondly your repository is implementing domain service interface and ISkill and things like that is adding more confusion. i am pretty sure if you organise your classes properly then you will find solution to your problem. For instance ApiController should use domain service, domain service should use repository and repository should deal with enties.
public class SkillsDomainService:ISkillsDomainService
{
public void AddSkill(string name){}
public void DeleteSkillById(int id){}
..... etc
}
public class Repository:IRepository
{
public T Get(int id){}
public IEnumerable<T>GetAll(){}
}
Then you need to bind your interfaces to concrete classed in ioc. things should work that way i am pretty sure.
Upvotes: 1
Reputation: 39297
It cannot resolve the dependency because it's looking for the concrete type but you never registered SkillsRepository
as that. Now you could change the registration to register the concrete type but that wouldn't be the best approach.
A better approach is to register SkillsRepository as its interfaces:
builder.RegisterType<SkillRepository>()
.As<ISkillsRepository>()
.InstancePerRequest();
And define ISkillsRepository
to inherit all the other interfaces like ISkill
that you want.
public interface ISkillsRepository : ISkill, IDomainService<Skill> { }
Don't register objects as concrete types and don't depend on concrete types in constructors.
public SkillsController(ISkillRepository skillRepository) :
base(skillRepository) ...
If you use concrete types as dependencies you create classes that cannot be tested using mocking frameworks.
Your use of SkillRepository : DomainService<Skill>, ISkill
is perplexing too. Why is it both a skill and a domain service for skills? Doesn't make much sense.
Upvotes: 3
Reputation: 100348
Exception clearly states:
Cannot resolve parameter 'Domain.Interfaces.ISkill skillRepository' of constructor 'Void .ctor(Domain.IDomainService`1[Model.Skill], Domain.Interfaces.ISkill)'.
You have only IDomainService
registered. But no ISkill
(the line is commented).
Also why does the ctor require 2 parameters? SkillRepository
implements both IDomainService<Skill>
and ISkill
so you should be able to pass it along:
public SkillsController(SkillRepository skillRepository) : base(skillRepository)
P.S.
I'd name it this way:
public class SkillRepository : ISkillRepository, IDomainService<Skill>
And I prefer everything to be either plural (SkillsControllers, SkillsRepository) or everything singular (SkillController, SkillRepository).
Upvotes: 1