Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
522 views
in Technique[技术] by (71.8m points)

c# - Binding autofac with webapi using generic repository

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?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...