【问题标题】:How to specify external dependencies an autofac module needs如何指定 autofac 模块需要的外部依赖项
【发布时间】:2020-09-10 09:38:12
【问题描述】:

我们使用 autofac 模块(通常在程序集级别)来注册包含在给定程序集中的类型。 通常,程序集对其他程序集提供的代码(接口)具有某种依赖性。 这些“外部”依赖由其他程序集的其他模块注册,所以一切都很好。

问题是:模块/程序集具有哪些外部依赖项并不明显,因此使用该模块的任何人都需要扫描代码以查找模块所需但未注册的类型。
我们“只”(一些例外,但在这里不相关)使用 lambda 注册,所以至少我们只需要查看 autofac 模块,但是,我仍在寻找一种方法来声明任何使用该模块的人都需要提供的依赖项。

最后,这个问题并不特定于 autofac,但我想知道我的 autofac 用户是否有任何关于声明外部依赖项并确保提供它们的最佳实践或技巧?

【问题讨论】:

    标签: autofac


    【解决方案1】:

    Autofac 没有为此提供开箱即用的功能,也没有任何计划。

    你可以做一些自定义的事情并创建一个属性来标记模块,但这将是你的实现的自定义。

    [RequiresService(typeof(IEmailSender))]
    [RequiresService(typeof(IOrderHandler))]
    public class MyModule : Module
    {
      // ...
    }
    

    但是像这样一个成熟的功能有一些逻辑挑战和不成文的额外目标,这就是为什么 Autofac 可能永远无法提供自动化处理它的原因。

    首先,修改模块的人需要记住修改正在完成的注册列表属性集。在小型团队中,可能能够保持这种纪律,但在具有不同技能组合的大型团队中,这两件事可能很快就会变得不一致。

    其次,虽然 只使用 lambda(我猜,每个内置的东西都有 new),但这并不是最常见的使用模式。这意味着修改底层组件类的人需要知道组件在哪个模块中注册并修改类型。这将底层组件与进行 DI 注册的模块耦合。

    第三,也与 lambdas 有关,这完全不适用于程序集扫描或开放泛型的批量注册。一般来说,泛型在这里是一个大问题,因为你可以有一个泛型构造函数参数,所以你的属性系统需要考虑到这一点,以及(可能)使用泛型约束。

    第四,如果服务通过一种内置关系(如IEnumerable<IService> 而不仅仅是IService)消费,我们还不清楚如何表达对服务的需求。同样,对于非常具体的 lambda 注册来说,问题不大,使用反射或扫描或其他任何方法都会崩溃。

    最后,总是有人会问,“给定这组模块,所有依赖项都满足了吗?”这意味着不仅需要某种方法来询问需要的内容,还需要了解模块提供的内容,这再次遇到了上述所有挑战,需要弄清楚如何使属性与模块中的内容保持一致,处理扫描、泛型等。

    无论如何,这是一个很长的解释,为什么它不是开箱即用的。抱歉,乱跑了。

    对于您非常具体的用例,我会使用属性,以便您可以通过代码查询需求,并根据需要轻松以编程方式报告事物。这完全是属性的用途。

    【讨论】:

    • 非常感谢您的详细解释。
    • 我知道解决此问题的技术解决方案存在众多挑战,因此我知道它没有内置机制。对于我们的用例,属性实际上可能是一个不错的解决方案(当然这意味着重复)。也许有一些(非技术)最佳实践来处理这种依赖关系?
    • 从文档的角度来看,为了找出用户在加载模块后必须注册的服务依赖项而必须访问可能数百个类,这会很痛苦吗?在模块本身内实现所需服务列表并保持集中定义不是更有用吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-01
    • 2018-03-30
    • 1970-01-01
    • 1970-01-01
    • 2013-11-05
    相关资源
    最近更新 更多