Autofac:注册彼此相关的服务,并使用name / key / meta / index解析

时间:2012-06-13 11:05:44

标签: c# autofac

我有autofac注册的情况,其中服务彼此相关。这就是我现在所拥有的:

var builder = new ContainerBuilder();

const string A = "A";
const string B = "B";

//Part 1
builder.RegisterType<ClassA1>().Named<IClass1>(A);
builder.RegisterType<ClassA2>().Named<IClass2>(A);

builder.RegisterType<ClassB1>().Named<IClass1>(B);
builder.RegisterType<ClassB2>().Named<IClass2>(B);

//Part 2
builder.Register(c => new ClassProcess(A, c.ResolveNamed<IClass1>(A), c.ResolveNamed<IClass2>(A))).Named<ClassProcess>(A).SingleInstance();
builder.Register(c => new ClassProcess(B, c.ResolveNamed<IClass1>(B), c.ResolveNamed<IClass2>(B))).Named<ClassProcess>(B).SingleInstance();

//Part 3
builder.Register(c => new ClassProcessDependency(c.ResolveNamed<ClassProcess>(B), c.ResolveNamed<ClassProcess>(A)));

在第1部分中,我定义了成对连接的两个基本类,IClass1和IClass2。

在第2部分中,我定义了一个连接这两个类的“进程”。这个过程实际上传递给了程序的其余部分,它采用了IEnumerable。

在第3部分中,我定义了这些进程之间存在的任何依赖关系,以便它们以正确的顺序执行。

我在这里寻找的是Autofac中的一些注册方法,它可以使用先前使用name / key / meta注册的服务,并使用该数据注册新服务。

编辑:请注意,我正在尝试查找是否有任何特定于Autofac的方法来执行此操作。

1 个答案:

答案 0 :(得分:3)

假设您在列表中有常量,可以通过...

进行枚举
IEnumerable<string> constants

...有没有理由你不能这样做?

foreach(var constant in constants)
{
  // Careful of the closure...
  var loopItem = constant;
  builder
    .Register(c =>
      new ClassProcess(
        loopItem,
        c.ResolveNamed<IClass1>(loopItem),
        c.ResolveNamed<IClass2>(loopItem)))
    .Named<ClassProcess>(loopItem)
    .SingleInstance();
}

除非我误解或误解,否则唯一阻止你的是标识符常量集不在列表中,这不是Autofac可以帮助你的。

如果您不喜欢在代码中使用foreach,则可以将其隐藏在模块中:

public class ProcessModule : Autofac.Module
{
  private IEnumerable<string> _constants;
  public ProcessModule(IEnumerable<string> constants)
  {
    this._constants = constants;
  }

  protected override void Load(ContainerBuilder builder)
  {
    // Put the foreach here and loop over this._constants.
  }
}

然后在主代码中注册模块:

builder.RegisterModule(new ProcessModule(constants));

如果你不能像那样循环,那么你的自动化方法可能会受到限制。或者,至少,你会看到更多的东西...... < EM>复杂

ContainerBuilder并不真正允许在注册时直接访问注册项目集,因此您必须进行更多低级别的欺骗。您可以实现IRegistrationSource来查找特定类型的所有命名注册并执行自动化。

不幸的是,如上所述,这个过程有点复杂,所以我不打算写出一个完整的解决方案。我会告诉你基本上我认为会起作用的,尽管,并为您提供一些参考,以查看源代码中的示例。

在开始这条道路之前Nick Blumhardt has a nice article on his blog解释了如何编写其中一条,并使用其中一个内置的Autofac来源作为示例。

首先,您需要实现Autofac.Core.IRegistrationSource这是用于执行添加隐式集合支持的接口(因此,如果您注册了五个IFoo实例你可以解决IEnumerable<IFoo>并且它有效。您可以在核心Autofac程序集中查看Autofac代码中的注册源示例:

注册源中的主要功能是RegistrationsFor方法,它返回源生成的注册列表:

IEnumerable<IComponentRegistration> RegistrationsFor(
  Service service,
  Func<Service, IEnumerable<IComponentRegistration>> registrationAccessor);

您对此方法的实施将检查传入的service是否为......

  • Autofac.Core.KeyedService(因为您正在命名所有服务)和
  • 你期望的类型。

如果所有行星都对齐,则会为IComponentRegistration返回ClassProcess并填写所有设置。

现在,这将变得更加困难,因为您的ClassProcess需要两个已命名的输入参数,您可能不希望注册命名的ClassProcess,除非您确定所有参数依赖项也已注册,因此您必须跟踪您看到的服务,并且只有在您看到它的所有依赖项后才会注册ClassProcess。(您可以使用{ {1}}来确定服务的名称是什么。)

此外,您不再使用KeyedService创建该组件注册,因此您必须在注册中找出与“生命周期范围”等内容相对应的所有正确设置,等等

获得ContainerBuilder后,您需要将其与IRegistrationSource联系起来。

ContainerBuilder

再次,如果您对此感兴趣,我会在Autofac树中查看这些源文件。由于复杂性,这不是许多人失败的道路。

老实说...... 如果你可以循环查看常数,我会这样做。为避免foreach循环,这似乎需要做很多工作。