【问题标题】:Ninject: Is it possible to have parent object in SingletonScope and child in TransientScope?Ninject:是否可以在 SingletonScope 中有父对象,在 TransientScope 中有子对象?
【发布时间】:2013-08-13 17:22:16
【问题描述】:

我已经为此绞尽脑汁好几个星期了……我现在拥有的是这样的:

  • 一堆*Service
  • 所有这些都依赖于通过 EF 访问数据库的不同 *Repository
  • 为了允许单元测试,DbContext 的派生被注入到存储库中。 (所以我不能使用using 来处理上下文)

为了正确处理注入的 EF 上下文,我可以在 InRequestScope() 或简单的自定义范围内运行我的依赖树 - InScope(c => new object()) 位于顶层,InParentScope() 位于所有其他级别。

这两种方法都会在每次请求期间创建和处置大量对象。此外,我们讨论的是单页应用程序,因此 95% 的查询(大约 50 个)将在 2 个请求期间执行,因此InRequestScope() 似乎不是一个好主意。 *Service 类也没有状态,因此可以是 InSingletonScope() 并且可以最大限度地减少对象创建的数量。

问题

是否有可能在InSingletonScope() 中有父类*Service*Repository 并以某种方式将EF DbContext 注入一个范围内,每次访问它时都会返回一个新实例,并使用NInject 尊重IDisposable ?

我知道在创建对象时会注入依赖项,但这仍然可以通过某种方式进行管理吗?

【问题讨论】:

    标签: c# architecture ninject


    【解决方案1】:

    不,这是不可能的。如果你仔细想想,你应该明白为什么。

    单例对象将在应用程序的整个生命周期中存在。 InRequestScope 对象在请求的整个生命周期内都存在。由于您的单例存储库将永远存在,并且它将保存对您的 DbContext 的引用(因为它是一个依赖项),这意味着如果您的存储库没有某种机制来释放 dbcontext,则无法对 dbcontext 进行垃圾收集。

    即使您确实提供了这种机制,您也必须有另一种机制来在下一次请求时重新获取新实例,因为不会创建新的单例存储库(因此不会调用它的构造函数,因此它的依赖关系将不会被解析,因此它将无法知道新的dbcontext)。

    因此,实际上,使 InRequestScope 对象成为单例对象的依赖项将有效地使 InRequestScope 对象成为单例对象,否则该对象将从单例对象下释放出来,这可能会很糟糕..

    另外,我希望与您不同的是,您的存储库确实具有状态。状态是 DbContext 本身。由于 Singleton 是应用程序范围的静态实例,因此您为使用您的应用程序的所有用户提供相同的实例,这意味着它也会提供相同的 DbContext,这是一个巨大的禁忌,因为您的用户会互相踩踏DbContext 状态。

    同样,您的服务也是有状态的,因为它们具有存储库,正如我刚刚指出的那样,它们具有 DbContexts,它们是有状态的。

    您想要做的只是让您的服务、存储库和 DbContext 都成为 InRequestScope。

    我不明白为什么这种方法会“在每个请求期间创建大量对象”。关键是它只为每个请求创建每个对象类型的一个实例。

    【讨论】:

    • 只有当我开始注入上下文时,状态问题才会进入方程。如果我的存储库只是在 using 块中新建一个上下文,那么就不会有状态问题。而且我确实发现,通过构造函数注入,单例将获得它需要的任何依赖项,而且只需要一次。我希望/梦想这种场景可以使用属性和调用拦截对 Ninject 不太熟悉。但我想这是不可能的:)
    • @juhan_h - 你当然可以手动强制注入属性,但这并不能解决状态问题,因为属性也是有状态的。也不会使用拦截,因为您充其量只能在调用方法时解析新上下文,但在具有单例状态的多用户环境中仍然存在并发问题。单例在应用程序范围内共享,而不是在请求范围内,甚至在用户范围内。您在单例中更改的任何状态都会影响应用的每个用户
    • @juhan_h - 但你真的想多了......并且过度优化。只需创建存储库 InRequestScope() 并完成它.. 这就是它们的目的。
    • 你说得对,属性会带来很多并发问题。我在输入这个时将它转换为 InRequestScope()。谢谢你的时间和拓宽我的视野。
    • 另一种方法是将 DbContextFactory 注入存储库。存储库中的方法将从工厂获取 dbContext,并且工厂将返回 InRequestScope 的 dbContext。这样,您就可以拥有 InSingletonScope 的服务和存储库,而不会在并发请求之间泄漏状态。不过,我仍然更喜欢使用 InRequestScope,它更易于推理。
    猜你喜欢
    • 1970-01-01
    • 2011-08-18
    • 2016-05-22
    • 1970-01-01
    • 1970-01-01
    • 2023-03-31
    • 2010-11-10
    • 2012-11-13
    • 1970-01-01
    相关资源
    最近更新 更多