Autofac键控注册

时间:2016-03-28 22:06:16

标签: c# dependency-injection autofac

有没有一种方法可以缩短以下方式,而不是逐个明确地注册这些类型:

builder.RegisterType<Repo1>().Keyed<IRepository>(typeof(Repo1));

builder.RegisterType<Repo2>().Keyed<IRepository>(typeof(Repo2));  

builder.RegisterType<Repo3>().Keyed<IRepository>(typeof(Repo3));

...

将每个存储库注册为IRepository接口,并将其类型作为键,以便我可以使用IIndex<Type, IRepository>

提前致谢

3 个答案:

答案 0 :(得分:1)

您可以注册一个函数,该函数将返回给定类型的存储库,以便在您的工作单元中使用。 Func<Type, IRepository>可以在Autofac中注册并注入您的工作单元。

// register your services as per Nico's answer
builder.Register...

// register a factory with Autofac
builder.Register<Func<Type, IRepository>>(x => {
    var context = x.Resolve<IComponentContext>();
    return y => { 
        return (IRepository) context.Resolve(y);
    };
});

// use the factory in your Unit of Work
class UnitOfWork
{
    readonly Func<Type, IRepository> _factory;

    public void SomeMethod(object o)
    {
        var repository = _factory(o.GetType());
        repository.DoSomething(o);
    }
}

答案 1 :(得分:0)

我不确定我是否正确地遵循了这个问题,通常IRepository指向具有通用功能的数据存储库(插入,更新,删除等)。但是autofac keyed services用于使用键名(或任何键类型)注册服务。如果是这种情况,您将不得不提出一个解决方案,可以找到所有Repo类型并在循环中单独注册它们。这可以使用Reflection实现。但是,每个对象Repo1Repo2等都需要一个共同的衍生物。

例如,假设每个Repo对象都来自接口IRepo,那么我们可以使用反射来查找类型为IRepo的{​​{1}}接口的所有实例然后遍历每个实例,将其注册到您的容器。像。的东西。

class

现在个人认为,当我通过我想要var iRepoType = typeof(IRepo); var repoTypes = Assembly.GetExecutingAssembly().GetTypes() .Where(type => type.IsClass && iRepoType.IsAssignableFrom(type)) .ToList(); foreach(var repoType in repoTypes) { builder.RegisterType(repoType).Keyed<IRepository>(repoType); } 的密钥typeof(Repo1)时,您正在说这个密钥服务时,这没有任何意义。因此,如果不使用Keyed服务注册每种类型的存储库,这不是一样的吗?

我在代码审核中发布了一个回答Repository patterns and classes的答案,这可能也有些兴趣。

答案 2 :(得分:0)

MEF获取一些灵感,我创建了一个类似的&#34;导出属性&#34;在autofac中实现这一点。 您可以创建一个Export属性,并将其作为

的每个IRepository实现使用它
  

[导出(typeof运算(IRepository))]

e.g. [Export(typeof(IRepository))]
     class Repo1:IRepository
     {}

在注册时,只需提取类型并使用RegisterGeneric(),注册您的组件。

/// <summary>
/// Export attribute to allow registering components using autofac. 
/// This attribute must be used for all pluggable components that require to be discovered dynamically.
/// </summary>
[AttributeUsage(AttributeTargets.Class)]
public class ExportAttribute:Attribute
{
    private Type type;

    public ExportAttribute(Type type)
    {
        this.type = type;
    }

    /// <summary>
    /// Provides the type (any interface) of Export
    /// </summary>
    public Type Type { get { return this.type; } }
}

    /// <summary>
    /// Registers components based on Export attribute containing their type information
    /// </summary>
    private void BuildContainer()
    {
       var allAssemblies = AssemblyInitializer.GetLoadedPlugins();
       allAssemblies.ForEach(assembly =>
        {
            var allTypes = assembly.GetTypes().Where(a => a.GetCustomAttribute(typeof(ExportAttribute)) != null).ToList<Type>();             

            allTypes.ForEach(y =>
            {
                var classType = ((ExportAttribute)(y.GetCustomAttribute(typeof(ExportAttribute)))).Type;

                if (!classType.IsInterface || !classType.IsAbstract || !classType.IsPublic) return;

                if (classType.Equals(typeof(IRepository<>)))
                {
                    builder.RegisterGeneric(y.GetTypeInfo()).Named(y.GetTypeInfo().Name, typeof(IRepository<>));
                }
                // Handle code for any other specific Interfaces                           
            });


        });

        this.Container = builder.Build();
    }