我正在尝试在 WinForms 应用程序中使用 Ninject(版本 3.0.1),我有几个(当前)自绑定服务类,我使用 Ninject 构建它们。一些服务类需要其他服务类(子服务)。这些服务类中的大多数都需要一个存储库来与数据库交互,因为我有一个抽象的 IRepository 接口。我需要为服务类中的整个服务层次结构拥有相同的存储库,因此我InCallScope()
在绑定 IRepository 时使用范围。目前我使用 XPO 作为 ORM 工具,所以我有一个 XpoRepository 实现,我绑定到它。请参阅我关于此场景的其他问题。
我的绑定看起来像这样:
Bind<IRepository>().To<XpoRepository>().InCallScope();
我没有ToSelf()
为每个服务类提供显式绑定,因此我假设当我从 Ninject 获取它们时,它们应该具有瞬态范围,我将其解释为我必须手动处置它们。
假设我有一个 Services1 和一个 Services2 服务类,它们都有一个 IRepository 类型的构造函数参数。现在假设 Services1 想使用 Services2 的一些方法,所以我向 Services1 添加了另一个构造函数参数,类型为 Services2。如果没有 Ninject,我会这样做:
var repo = new MyRepository(); // implementing IRepository
var service1 = new Services1(repo, new Services2(repo));
我在后台线程中使用其中一项服务(使用 TPL),在这样的循环中:
while (true) {
if (CancellatioPending())
break;
using (var service = _kernel.Get<Service1>())
{
// do some stuff using the service class
}
Thread.Sleep(20*1000);
}
在使用 Ninject 之前我有相同的结构,所以我(我认为)正确地实现了对每个对象的处理,包括正确位置的存储库。但是,我注意到,由于我为此使用了 Ninject,因此我的应用程序中存在很大的内存泄漏,并且它每 2-3 小时就会因 OutOfMemoryException 而崩溃。我在循环中放置了一个断点,并注意到 Ninject 缓存有数千个条目,其中充满了已处置的 XpoRepository 对象。我猜它们是由我处理的,但我不确定是谁调用了 dispose 方法。
为什么 Ninject 持有这些已处置的对象?我希望当我在 using 块的末尾处置主要服务时(这是 IRepository 对象的范围,由于 InCallScope()),其范围内的每个对象都应该由 Ninject 处置和释放。
编辑:在任何评论或回答为什么这种模式不好之前,我知道它可能会更好。我知道我可以提取服务接口以实际使用 DI 并提高可测试性,我也知道我可能应该使用 aFunc<IRepository>
作为构造函数参数并注入其中,就像每个服务都可以有自己的责任来处理存储库。只是我目前没有时间进行此类重构。