Замок Windsor PerWebRequest объект вводится в объект Singleton без ссылки на него в поле

Мы создали одноэлементный объект (SsoSettingsProvider), в который вводим объект с образом жизни PerWebRequest (IReservationService в нашем примере это клиент WCF). В конструкторе мы используем этот объект для получения некоторых данных и помещаем эти данные в приватное поле.

public class SsoSettingsProvider : ISsoSettingsProvider
    {
        readonly LogonSettings _logonSettings;


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

Если мы посмотрим на возможные несоответствия образа жизни в Виндзорском замке, то будет сказано:

"Компонент SsoSettingsProvider / ISsoSettingsProvider" с образом жизни Singleton зависит от "позднего связывания IReservationService" с образом жизни PerWebRequest. Этот тип зависимости обычно нежелателен и может привести к различным ошибкам ".

Эта информация говорит о том, что есть только возможность, но в этом случае я думаю, что это не проблема, потому что на внедренный объект нет ссылки в поле, поэтому он может быть собран мусором. я прав?

1 ответ

Решение

в этом случае я думаю, что это не проблема, потому что на внедренный объект нет ссылки в поле, поэтому он может быть собран мусором. я прав?

Замок Виндзор предупреждает о пленнических зависимостях. Основная проблема не столько в том, что экземпляры не являются сборщиком мусора, но в классе будет повторно использоваться экземпляр, который не предназначен для повторного использования.

Простой пример, когда вы вводите DbContext в класс, который настроен как синглтон. Хотя это приведет к DbContext поддерживается до тех пор, пока его единый потребитель не выйдет из области видимости (что обычно происходит, когда заканчивается приложение). DbContextоднако не следует повторно использовать несколько запросов. Во-первых, потому что это просто не потокобезопасно. Кроме того, он очень скоро устареет, что заставляет его возвращать кэшированные данные вместо повторного запроса к базе данных.

По этой причине мы регистрируем DbContext обычно как Scoped. Это, однако, означает, что все его потребители должны жить не более DbContext, чтобы предотвратить его нарушение приложения. Это то, о чем Касл предупреждает.

В вашем случае, однако, вы не храните IReservationService в частном поле SsoSettingsProvider, Это все еще будет проблемой, потому что было бы разумно ожидать, что объекты, которые IReservationService возврат не переживает IReservationService (иначе IReservationService будет зарегистрирован как синглтон). Так как с точки зрения SsoSettingsProviderнет никакого способа узнать, безопасно ли хранить LogonSettingsГораздо лучше не хранить его вообще.

Кроме того, как выражено здесь, конструкторы инъекций не должны вообще использовать свои зависимости. Это приводит к медленному и ненадежному составу объекта.

Поэтому, даже если вы проанализировали свой дизайн и точно знаете, что это работает в вашем конкретном случае, я бы посоветовал вам сделать одно из следующих действий:

  • хранить IReservationService как частное поле в SsoSettingsProvider и позвонить GetSSOSettings только когда один из SsoSettingsProviderзовут и мешают запоминать LogonSettings, Это заставляет вас сделать либо SsoSettingsProvider ограничен или IReservationService синглтон. Так или иначе IReservationService Может быть синглтон это только то, что вы можете узнать.
  • В случае SsoSettingsProvider заинтересован только в LogonSettings, а также LogonSettings это постоянное значение, которое не изменится после запуска приложения, вы должны ввести LogonSettings прямо в SsoSettingsProviderконструктор. Это упрощает SsoSettingsProvider и толкает загрузку LogonSettings в корень композиции.
Другие вопросы по тегам