Autofac - 注册通用约束

时间:2016-11-21 18:51:50

标签: c# entity-framework asp.net-web-api asp.net-web-api2 autofac

我正在尝试使用Autofac注册通用组件。我遇到的问题类似于下面链接中的问题(错误消息是相同的)。 Binding autofac with webapi using generic repository

我正在使用洋葱架构(http://jeffreypalermo.com/blog/the-onion-architecture-part-1/)。 DbContexts位于单独的层中,而业务层是获取数据并执行与业务规则相关的各种事务的层。上层只会知道IBaseDbManager接口。我有一个垂直层,负责解决依赖关系。

在我的代码示例和Autofac配置下面:

商业类:

public class BaseDbManager<TContext> : IBaseDbManager where TContext : DbContext, IBaseContext
{
    private readonly TContext _context;

    public BaseDbManager(TContext context)
    {
        _context = context;
    }

    public Partner GetPersonInfo(Expression<Func<Person,bool>> predicate)
    {
        var person = _context.Persons.Where(predicate).FirstOrDefault();
        return person;
    }
}

业务界面:

public interface IBaseDbManager
{
    Partner GetPersonInfo(Expression<Func<Person, bool>> predicate);
}

DB CONTEXT:

   [Database]
    public class BaseContext : DbContext, IBaseContext
    {
        public BaseContext()
            : base((string) ConnectionHelper.BaseConnectionString())
        {
            Database.SetInitializer<BaseContext>(null);
        }

        public virtual DbSet<Person> Persons { get; set; }
    }

上下文接口:

public interface IBaseContext
{
    DbSet<Partner> Partners { get; set; }
}

AUTOFAC MODULE:

protected override void Load(ContainerBuilder builder)
{
    builder.RegisterType<BaseContext>().As<IBaseContext>().InstancePerLifetimeScope(); 
    builder.RegisterType(typeof(BaseDbManager<>)).As<IBaseDbManager>().InstancePerLifetimeScope();
}


问题是Autofac不知道如何在没有无参数构造函数的情况下解析IBaseDbManager。我需要通过Autofac解决TContext。如何配置Autofac来解决这些问题?我尝试注册为通用的,并基于构造函数,它也不起作用。如果我向约束添加new()并在无参数构造函数中创建一个实例,那么它可以工作......我不想这样解决它。

我错过了什么?

2 个答案:

答案 0 :(得分:2)

  

问题是Autofac不知道如何在没有无参数构造函数的情况下解析IBaseDbManager。

这不是问题。构造函数不是问题,Autofac不会对构造函数构成任何约束。

这里的问题是,给定open-generic BaseDbManager<T>,Autofac不知道要创建它的封闭通用版本,因为给定的IBaseDbManager抽象是非泛型的。它无法为您推断出通用类型。

有几种解决方案,但由于应用程序中不同上下文类型的数量很可能非常有限(通常只有1),因此在注册中指定此上下文类型最有意义。例如:

builder.RegisterType(typeof(BaseDbManager<BaseContext>)).As<IBaseDbManager>()
    .InstancePerLifetimeScope();

如果BaseContext是你唯一的上下文类型,那么使BaseDbManager<T>非泛型更有意义,因为如果你实际上计划改变类型参数T那么它只是有意义的{1}}。

  

我有两个与TContext约束匹配的对象(BaseContext和FakeBaseContext)。 BaseContext查询数据库,FakeBaseContext使用专门为单元测试创​​建的伪数据。

这似乎不是另一个上下文类的正当理由;上下文是一组实体的定义;在测试期间,您拥有相同的实体集。

答案 1 :(得分:0)

在查看Autofac文档的几个部分之后,我发现注册文件与Steven的方法相结合,允许Autofact正确解析依赖关系(参见下面的链接):

http://docs.autofac.org/en/latest/register/parameters.html?highlight=WithParameter

模块注册我的最终编码如下:

protected override void Load(ContainerBuilder builder)
{
    builder.RegisterType<BaseContext>()
           .As<IBaseContext>()
           .InstancePerLifetimeScope();

    builder.RegisterType<BaseDbManager<BaseContext>>().As<IBaseDbManager>()
           .WithParameter(new TypedParameter(typeof(BaseContext), new BaseContext()))
           .InstancePerLifetimeScope();
}

额外反馈将不胜感激。我会继续重构我的代码,因为我认为它可以改进。