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

时间:2011-12-20 13:59:30

标签: c# inversion-of-control autofac

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

  1. IRepository<>,我的存储库界面;
  2. DbContextRepository<>,使用EntityFramework的DbContext的存储库的通用实现;
  3. 程序集中的一些已关闭类型的存储库,例如PersonRepository : DbContextRepository<Person>;
  4. 还有一个RepositoryDecorator<>,用一些标准的额外行为来装饰我的存储库;
  5. 我正在使用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");
    

    我想做的是:

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

      但是当我尝试解析一个IRepository<Person>,其中具有一个封闭类型的实现时,它还为我提供了一个装饰的DbContextRepository,而不是一个装饰的PersonRepository。

1 个答案:

答案 0 :(得分: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();