如何使用autofac注册开放泛型类型,封闭泛型类型和装饰?

rca*_*val 4 c# inversion-of-control autofac

我使用Autofac作为我的IoC容器.我有:

  1. IRepository<>,我的存储库界面;
  2. DbContextRepository<>,使用EntityFramework的DbContext的存储库的通用实现;
  3. 比如说PersonRepository : DbContextRepository<Person>,程序集中的一些封闭类型的存储库 ;
  4. 而a RepositoryDecorator<>,用一些标准的额外行为来装饰我的存储库;

我正在使用autofac将它们全部注册为:

builder.RegisterGeneric(typeof(DbContextRepository<>))
            .Named("repo", typeof(IRepository<>));

builder.RegisterGenericDecorator(
                typeof(RepositoryDecorator<>),
                typeof(IRepository<>),
                fromKey: "repo");            

var repositorios = Assembly.GetAssembly(typeof(PersonRepository));
builder.RegisterAssemblyTypes(repositorios).Where(t => t.Name.EndsWith("Repository"))
          .AsClosedTypesOf(typeof(IRepository<>))
          .Named("repo2", typeof(IRepository<>))
          .PropertiesAutowired();

builder.RegisterGenericDecorator(
               typeof(RepositoryDecorator<>),
               typeof(IRepository<>),
               fromKey: "repo2");
Run Code Online (Sandbox Code Playgroud)

我想要做的是:

  1. 注册DbContextRepository<>为通用实施IRepository<>;
  2. 然后注册已关闭的类型存储库,以便它们可以在需要时重载先前的注册;
  3. 然后装饰它们,当我要求容器解析IRepository时,它给我一个RepositoryDe​​corator,它具有正确的IRepository实现,是DbContextRepository或已经注册的封闭类型.

当我尝试解析一个IRepository<Product>没有闭合类型实现的时,它会正确返回一个装饰的DbContextRepository.

但是,当我尝试解决的IRepository<Person>,它一个封闭式的实现,这也给了我一个装饰DbContextRepository,而不是装饰PersonRepository.

def*_*mer 7

问题是Named("repo2", typeof(IRepository<>))没有做你的想法.您需要为正在扫描的类型明确指定类型.

static Type GetIRepositoryType(Type type)
{
    return type.GetInterfaces()
        .Where(i => i.IsGenericType
            && i.GetGenericTypeDefinition() == typeof(IRepository<>))
        .Single();
}

builder.RegisterAssemblyTypes(this.GetType().Assembly)
    .Where(t => t.IsClosedTypeOf(typeof(DbContextRepository<>)))
    .As(t => new Autofac.Core.KeyedService("repo2", GetIRepositoryType(t)))
    .PropertiesAutowired();
Run Code Online (Sandbox Code Playgroud)