我们在基于.NET的产品中广泛地使用了依赖注入,使用了Ninject库。我们的大部分代码都被整齐地打包在Ninject模块中。其中一些模块包含的后台服务应该在系统启动或DI模块加载时立即启动。我们所做的就是让ISystemInitializer服务运行所有启动任务,并在系统启动时运行所有后台服务。它们已经发展到了巨大的尺寸,我想知道我们是否会这样做。
我想知道在依赖注入模块上运行启动操作和启动服务并在卸载模块时停止它们是否有意义。这将大大减少主应用程序和各个模块之间的依赖关系。缺点是,在实际上只能绑定类型的DI模块中实际启动服务感觉很脏。
我是否可以采取其他方法将模块初始化与模块绑定分离?
发布于 2020-09-14 15:54:00
管理实际运行时通常应该留给顶级项目(从现在起,为了我的理智起见,TLP)。它应该能够决定它做什么和不使用什么。这与DI容器本身的目标本质上是相同的:将控制权交给使用者。
为了适应这个目标,TLP需要能够主动地选择启动/停止(当停止相关时)一个后台工作人员。如果TLP不能控制这一点,那么您就没有真正对所有者/调用者进行反向控制。
但是,这并不意味着不允许您的库/模块提供一个整洁的(不是自动启动的)后台工作人员,以便尽可能地保持您的TLP的轻量级。除了启动该员工的决定之外,其他一切都可以由您的模块提供--但是启动的决定应该保持在TLP的控制之下。
为了回答你问题的几个部分:
其中一些模块包含了应该在系统启动后立即启动的后台服务。
TLP是决定系统何时被认为已经完成其运行时初始化阶段的人,因此TLP也控制后台服务何时启动是有意义的。
我们所做的就是让
ISystemInitializer服务运行所有启动任务,并在系统启动时运行所有后台服务。
您没有发布任何代码,也没有详细说明您的ISystemInitializer位于何处,因此很难准确判断您现在在做什么。你问了一个非常抽象的问题,这个答案只能像你的问题那样具体。
我猜ISystemInitializer就在TLP的某个地方。如果是的话,那它就在正确的地方。不过,..。
它们已经发展到了巨大的尺寸,我想知道我们是否会这样做。
...from的声音,您的ISystemInitializer可能需要一些重构。
但这并不意味着您需要更改初始化逻辑的位置。您的方法可能是正确的,可能只是需要将其分解为不同的类/职责,以使事情更容易管理,而不需要真正改变其发生的位置。
根据你所说的,我推断这种方法大致正确,只是目前还没有被分解成容易消化的块。
我想知道在依赖注入模块上运行启动操作和启动服务并在卸载模块时停止它们是否有意义。
这样做并不是不可能的,但我对这种方法感到担忧。你几乎没有意识到你的TLP到底在模块中发生了什么。
尽管如此,我关心的问题可以很容易地解决,例如,让TLP显式地调用一个简单的MyModule.StartBackgroundServices()方法,并让模块自己决定它需要启动什么(即在StartBackgroundServices()方法体中)。
通过显式的方法调用,您仍然遵循我最初的建议,即TLP保留对某件事情是否启动的最终控制权。
此示例确实要求模块的后台服务是包处理,但在您的情况下,这在上下文上可能是合适的。如果您的TLP需要更多的特定控件,那么提供它需要的特定控件。
这将大大减少主应用程序和各个模块之间的依赖关系。
这在很大程度上取决于我们在这里讨论的依赖项有多少。一般来说,人们的期望是,按照IoC的思想目标,TLP被有意赋予对所有依赖的控制权。
用一句众所周知的话说:拥有强大的权力就意味着巨大的责任。这里更多的观点是:随着控制的反转,必须处理依赖关系图或将处理信息委托给受信任的源,例如您的模块。
尽管如此,这并不意味着你不能改善这里的情况。例如,如果您的所有后台服务都采用完全相同的格式,则可以大大简化此处理逻辑:
IBackgroundService契约IBackgroundServiceIBackgroundService服务并迭代地启动它们。在您的例子中,使用NInject,您可以依赖于多注入,它允许在同一服务类型下注册多个服务,然后在构造函数中注入所有这些服务的数组。
对于TLP来说,这只能归结为:
public class SystemInitializer
{
private readonly IBackgroundService[] _services;
public SystemInitializer(IBackgroundService[] services) // <-- NInject will give you this array based on your DI registration
{
_services = services;
}
public void StartAll()
{
foreach(IBackgroundService service in services)
{
service.Start();
}
}
}这只是一个过于简化的例子,但是不管您有多少后台服务,这个示例都能工作。当您已经开发了更多的后台服务时,它不需要扩展,所以它是OCP友好的,并且它将TLP中所需的依赖保持在一个绝对最小的水平。
但是同时,TLP仍然有必要的控制来处理特定的依赖项,例如,它可以过滤掉它不想运行的任何后台服务。
最大限度地控制,最小化依赖的杂耍。
https://softwareengineering.stackexchange.com/questions/415889
复制相似问题