使用通用存储库将autofac绑定到web api

时间:2014-10-12 02:16:40

标签: c# asp.net-web-api dependency-injection autofac

我正在尝试将autofac与存储库一起使用,我正在尝试添加一些小的泛型,以尝试减少我正在编写的重复代码的数量。但是,我正在绕圈试图让autofac为我工作

所以我创建了一个处理标准crud操作的域服务和接口

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);
    }

接口:

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);
}

我正在使用我的回购并不是什么特别的

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;
    }
}

最后我连接了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;

我的网络API控制器看起来像

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;
    }

我得到一个例外:

  

“没有任何建设者发现   类型上的'Autofac.Core.Activators.Reflection.DefaultConstructorFinder'   'Api.EndPoints.Skills.SkillsController'可以用。调用   可用的服务和参数:\ \无法解析参数   'Domain.Repository.SkillRepository skillRepository'的构造函数   'Void .ctor(Domain.Repository.SkillRepository)'。“

有什么明显的东西我做错了吗?

3 个答案:

答案 0 :(得分:3)

它无法解决依赖关系,因为它正在寻找具体类型,但您从未注册过SkillsRepository。现在您可以更改注册以注册具体类型,但这不是最好的方法。

更好的方法是将SkillsRepository注册为其接口:

builder.RegisterType<SkillRepository>()
    .As<ISkillsRepository>()
    .InstancePerRequest();

定义ISkillsRepository以继承所需的所有其他接口,例如ISkill

public interface ISkillsRepository : ISkill, IDomainService<Skill> { }

不要将对象注册为具体类型,也不要依赖于构造函数中的具体类型。

  public SkillsController(ISkillRepository skillRepository) : 
      base(skillRepository) ...

如果使用具体类型作为依赖项,则创建无法使用模拟框架进行测试的类。

您对SkillRepository : DomainService<Skill>, ISkill的使用也令人困惑。为什么它既是技能的技能,也是技能的域名服务?没有多大意义。

答案 1 :(得分:1)

例外明确指出:

  

无法解析参数&#39; Domain.Interfaces.ISkill skillRepository&#39;构造函数&#39; Void .ctor(Domain.IDomainService`1 [Model.Skill],Domain.Interfaces.ISkill)&#39;。

您只注册了IDomainService。但没有ISkill(该行已注释)。

为什么ctor需要2个参数? SkillRepository同时实现IDomainService<Skill>ISkill,因此您应该可以将其传递:

public SkillsController(SkillRepository skillRepository) : base(skillRepository)

P.S。

我以这种方式命名:

public class SkillRepository : ISkillRepository, IDomainService<Skill>

我更喜欢一切都是复数(SkillsControllers,SkillsRepository)或一切都是单数(SkillController,SkillRepository)。

答案 2 :(得分:1)

在我看来,你应该首先为你的类理清名称,这使得很难理解代码本身。其次,你的存储库正在实现域服务接口和ISkill,这样的事情增加了更多的混乱。我很确定如果您正确组织课程,那么您将找到解决问题的方法。 例如ApiController应该使用域服务,域服务应该使用存储库和存储库应该处理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(){}
}

然后你需要将你的接口绑定到ioc中的具体类。事情应该这样,我很确定。