在Autofac中,如何使用装饰器替换默认注册?

时间:2017-04-02 12:50:21

标签: c# autofac

我在Autofac(v4.4.0,.NET 4.6.1)中遇到了一些意外行为,我觉得这可能是一个错误。

来自documentation

  

默认注册

     

如果多个组件公开同一服务, Autofac将使用最后注册的组件作为该服务的默认提供商

e.g。如果我这样做:

    builder.RegisterType<FooOne>().As<IFoo>();
    // Next line replaces default IFoo implementation
    builder.RegisterType<FooTwo>().As<IFoo>();

当我从容器中解析FooTwo时,我希望(并获得)IFoo的实例。

但是,如果我已经注册了IFoo,并且我使用RegisterDecorator<T>函数注册IFoo的装饰器,则不会替换默认注册IFoo。 e.g:

    // Register FooOne directly
    builder.RegisterType<FooOne>().As<IFoo>(); // (1)
    // Now set up a decorator
    builder.RegisterType<FooOne>().Named<IFoo>("foo");
    builder.RegisterDecorator<IFoo>((c, inner) =>
      new DecoratorFoo(inner), fromKey: "foo");

IFoo解析为 未修饰 FooOne。这感觉与我不一致;违反了principle of least astonishment

您可能声称我根本不应该使用第(1)行(并且代码在没有它的情况下正常工作) - 但它是一个公认的习惯用法(例如here)来使用用于替换注册的插件。

在我的情况下,这个bug在一个相当大的代码库中得到满足,其中包装类型已经由一个约定注册,现在需要进行修饰,需要重新考虑如何完成注册。

适用于LINQPad的Gist证明问题是here

我缺少观察到的行为的设计理由吗?有没有办法让装饰器注册替换默认值?

1 个答案:

答案 0 :(得分:4)

您可以查看有关您的问题here的未解决问题。在讨论中你可以找到这种行为背后的推理。正如我所理解的那样,他们正试图解决这个问题,但事实证明,由于autofac的内部运作,这并不是一件容易的事。

同时作为一种解决方法,您可以像这样注册您的装饰者:

builder.Register((cnt, parameters) => new DecoratorFoo(cnt.ResolveNamed<IFoo>("foo", parameters))).As<IFoo>();

这也将修复另一个问题\ bug(在此stackoverflow question中提到),您可能会遇到(或不会)以后,与事实相关的装饰器不会将参数传播到装饰对象。