长时间运行的Windows服务中的依赖注入 - 组合根本正确的想法?

时间:2013-05-18 15:03:53

标签: c# dependency-injection windows-services ninject

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

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

但是,我不明白这是如何适用于所有情况的。我看到在应用程序启动时可以组成完整根目录的情况下,或者像MVC那样,框架中每个请求都使用IoC引擎的情况下,它会如何完美。但是,对于长期运行的服务,我认为在最好的情况下效率很低,而且在某些情况下不可能预先创建所有对象。我无法想象能够编写一个非平凡的服务来获取它可能需要的所有对象,并且永远不需要在生活中创建新的对象。

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

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

最后一部分并不严肃,但我仍然想知道如何妥善解决这个问题。

2 个答案:

答案 0 :(得分:15)

可以将问题分成两部分:

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

如何管理范围

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

听起来不像服务定位器吗?是的,但它不是服务定位器。您可以在Mark Seemann blog: Abstract Factory or Service Locator?了解更多信息。

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

如何管理生命周期

如果您打算以24-7运行您的服务,这是更复杂和重要的部分。在这里,我只能给你一些实用的建议:

  • 对于此类服务,外部依赖方面的失败(即数据库,服务)是常规的,而不是例外
  • 不要在针对性能或重用的代码中自行保留对依赖项的任何引用
  • 不要使用复杂的生命周期(例如Ninject的命名范围)
  • 尽快释放依赖关系。配置Ninject为您管理它们。
  • 考虑依赖项的超时,重新创建新实例
  • 可以用于长时间运行的任务,创建单独的Kernel实例,并确保之后已将它们处理掉

答案 1 :(得分:0)

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

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

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

以你的直觉去做,并保持精益和放松的意思。