注入 Singleton 对象的 Castle Windsor PerWebRequest 对象没有在字段中引用它

Castle Windsor PerWebRequest object injected in Singleton object without referencing it in field

我们创建了一个单例对象 (SsoSettingsProvider ),我们在其中注入了具有生活方式 PerWebRequest 的对象(IReservationService 在我们的示例中它是 WCF客户)。在构造函数中,我们使用这个对象来获取一些数据,并将这些数据放在一个私有字段中。

public class SsoSettingsProvider : ISsoSettingsProvider
    {
        readonly LogonSettings _logonSettings;


        public SsoSettingsProvider(IReservationService reservationService)
        {
           _logonSettings = reservationService.GetSSOSettings();
        }        
    }

如果我们看看温莎城堡可能存在的生活方式不匹配,它会说:

"Component 'SsoSettingsProvider / ISsoSettingsProvider' with lifestyle Singleton depends on 'late bound IReservationService' with lifestyle PerWebRequest This kind of dependency is usually not desired and may lead to various kinds of bugs."

这个信息说只有可能性,但在这种情况下我认为这不是问题,因为注入的对象没有在字段中引用,所以它可以被垃圾收集。我说得对吗?

in this case i think it is not a problem because injected object is not referenced in a field so it can be garbage collected. am i right?

温莎城堡发出关于 Captive Dependencies 的警告。主要问题不是实例没有被垃圾收集,而是 class 将重用一个不打算重用的实例。

简单的例子是当你将一个 DbContext 注入到一个配置为单例的 class 中时。尽管这将导致 DbContext 一直保持活动状态,直到其单例使用者超出范围(通常是应用程序结束时)。但是,DbContext 不应在多个请求中重复使用。其一,因为它根本不是线程安全的。最重要的是,它很快就会过时,这会导致它 return 缓存数据,而不是重新查询数据库。

出于这个原因,我们 register DbContext typically as Scoped。然而,这确实意味着它的所有消费者最多应该与 DbContext 一样长,以防止它破坏应用程序。这就是 Castle 警告的内容。

然而,在您的情况下,您没有将 IReservationService 存储到 SsoSettingsProvider 的私有字段中。这仍然是一个问题,因为可以合理地预期 IReservationService return 的对象不会比 IReservationService 长(否则 IReservationService 将被注册为 Singleton ).因为从SsoSettingsProvider的角度来说,它无法知道存储LogonSettings是否安全,所以根本不存储[=56]会更好=].

最重要的是,如 here 所述,注入构造函数根本不应使用它们的依赖项。这会导致缓慢且不可靠的对象组合。

因此,即使您可能已经分析了您的设计并确定这在您的特定情况下有效,我还是建议您执行以下操作之一:

  • IReservationService 作为私有字段存储在 SsoSettingsProvider 中,仅当调用 SsoSettingsProvider 的成员之一时才调用 GetSSOSettings 并防止存储 LogonSettings。这会迫使您创建 SsoSettingsProvider 作用域或 IReservationService 单例。 IReservationService能不能单例,就看你自己了。
  • 如果SsoSettingsProvider只对LogonSettings感兴趣,而LogonSettings是应用程序启动后不会改变的常量值,你应该注入LogonSettings直接在 SsoSettingsProvider 的构造函数中。这简化了 SsoSettingsProvider 并将 LogonSettings 加载到 Composition Root。