10

我正在编写一个 Windows 服务(如果一切按计划进行)将一次运行数月。在服务的整个生命周期中,它将维护多个 WCF 服务(用于与其他本地应用程序通信的命名管道),它将运行一个嵌入式数据存储(可能是 RavenDB,这或多或少与这个问题无关),并且它将使用一些第三方软件来维护 SIP 服务(VoIP 功能)。我面临的一些挑战意味着必须对事件做出反应并创建一些新的业务对象来处理这些事件所代表的内容。

现在,我已经阅读了 Mark Seemann 的书(至少是本次讨论的相关部分),并且我理解为什么服务定位器不好,以及为什么在组合根(在我的情况下是服务起点)中处理它是好的 - 在一般情况。

但是,我不明白这如何适用于每种情况。我看到在你可以在应用程序开始时组合你的整个根的情况下,或者在框架的每个请求使用 IoC 引擎的 MVC 之类的情况下,它是多么完美。但是,对于长期运行的服务,我想在最好的情况下会效率低下,并且在某些情况下不可能预先创建所有对象。我无法想象能够编写一个重要的服务,它可以预先获取它可能需要的所有对象,并且随着生活的继续,永远不需要创建新的对象。

现在,这还不足以将我引向黑暗面并承担隐藏依赖项的代价,就像服务定位器会让我做的那样。但是在这里做什么是正确的?如果我有一个 CallHandlerService 需要创建以响应每个传入呼叫(例如,因为它使用昂贵的非托管资源),我该怎么做?

组合根 + 只是一点点服务定位器?

最后一部分并不严重,但我仍然很想知道如何正确解决这个问题。

4

2 回答 2

16

可以将问题分为两个:

  • 如何管理范围
    • 避免预先创建所有可能的依赖项
    • 创建所需的依赖项
  • 如何管理生命周期
    • 保留对已创建依赖项的引用
    • 如果可能,重用依赖项
    • 尽快清理它们

如何管理范围

您可以定义几个专门的抽象工厂的接口或实现,它们中的每一个都将仅限于管理它自己的特殊类型的依赖关系。例如:一个用于数据库相关的依赖项,另一个用于 SIP 相关。然后您可以自己注入工厂,而不是依赖项,并从中检索依赖项。

听起来不像服务定位器吗?是的,但它不是服务定位器。您可以在Mark Seemann 博客上阅读更多内容:抽象工厂还是服务定位器?.

如果抽象工厂没问题,请查看Ninject.Extensions.Factory以根据您的IKernel配置自动创建它们

如何管理生命周期

如果您要 24-7 全天候运行您的服务,这是更复杂和重要的部分。在这里,我只能给你几个实用的建议:

  • 对于此类服务,外部依赖端(即数据库,服务)的故障是常规的,而不是例外
  • 不要在旨在提高性能或重用的代码中保留对依赖项的任何引用
  • 不要使用复杂的生命周期(例如 Ninject 的命名范围)
  • 尽快释放依赖项。配置 Ninject 为您管理它们。
  • 考虑依赖项的超时,以重新创建新实例
  • 可能用于长时间运行的任务,创建单独的实例Kernel,并确保您在之后处理它们
于 2013-05-19T05:18:08.933 回答
0

在我看来,依赖注入(通常用于提供服务)在某种程度上是一种黑暗艺术,并且确实需要对如何以及何时正确使用它有所了解。

根据我的经验,尝试调试和注入依赖项存在错误或异常的应用程序充其量是一个乏味的过程,特别是如果特定对象是隐藏在同一接口后面的几个对象之一。这就是为什么使用该接口对所有对象进行单元测试很重要的原因,因为您永远不知道哪个对象会因相同的输入而失败。

您的依赖注入最好在您的服务启动时使用,为每种类型的调用创建处理程序,然后在每个调用进入时,适当地调度。但是,我认为尝试创建一个对象来处理每个调用会增加更多开销和复杂性。

跟着你的直觉走,保持精益求精。

于 2013-05-18T15:18:21.863 回答