Unity Container ResolutionFailedException, когда сопоставление правильно в файле конфигурации

Я использовал ServiceLocator, который я DIing с Unity

public ServiceLocator(IUserStore userStore, IProdcutsStore productsStore, ...etc) {}

public IUserStore UserStore 
{ 
    get { return userStore; }
}

Все это работало нормально, но я хотел ленивое создание репозиториев, поскольку они используются довольно редко.

Итак, мой ServiceLocator теперь выглядит так

    public ServiceLocator(IUnityContainer container) {}

    public IUserStore UserStore 
    { 
        get { return (IUserStore)container.Resolve(typeof(IUserStore)); }
    }

   //  ...etc

Теперь я получаю действительно бесполезную ошибку ResolutionFailedException

Ошибка разрешения зависимости, type = "DomainModel.DataServices.Interface.IUserStore", name = "". Сообщение об исключении: текущая операция сборки (сборка ключа Build Key[DomainModel.DataServices.Interface.IUserStore, null]) не удалась: текущий тип, DomainModel.DataServices.Interface.IUserStore, является интерфейсом и не может быть создан. Вам не хватает сопоставления типов? (Тип стратегии BuildPlanStrategy, индекс 3)

Говорить мне, что мой тип интерфейса не может быть создан, потому что это интерфейс, довольно бессмысленно. Я знаю, что это интерфейс, поэтому контейнер должен решать его за меня!

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

Что мне не хватает, что означает, что что-то где-то должно измениться, чтобы ленивая загрузка была такой?

Обновление: я предполагаю, что здесь происходит то, что когда я ввожу контейнер в ServiceLocator, «основной» контейнер каждый раз создает экземпляр нового контейнера, который затем не настраивается должным образом. Я думаю, может быть, мне нужен какой-то способ указать, что я должен передать this в качестве контейнера, а не разрешать его с помощью нового экземпляра.


person fearofawhackplanet    schedule 13.09.2010    source источник


Ответы (1)


Вы идете в несколько неправильном направлении... Сначала у вас был тестируемый класс, который объявлял свои зависимости в конструкторе, а вы превратили его в не тестируемый, запрашивая "что-то" внутри контейнера... Ничего хорошего =(

Вы должны либо реализовать какой-то фабричный интерфейс для вашего дорогостоящего объекта и потребовать его в конструкторе, либо (если можете) переключиться на Unity 2.0 и использовать Автоматические фабрики:

public ServiceLocator(Func<IUserStore> userStoreBuilder)

//...

public IUserStore UserStore 
{ 
   get { return userStoreBuilder(); }
}

Если вы хотите создать экземпляр этого объекта только один раз, вы можете добавить кэширование к этому свойству или с .NET 4.0 вы можете попробовать запрос Lazy в конструкторе.

P.S. О, да. И отвечая на ваш конкретный вопрос =) Если вы все еще хотите внедрить экземпляр своего контейнера куда-то еще, вам нужно сначала зарегистрировать его внутри себя =)

container.RegisterInstance<IUnityContainer>(container);

Исправить (см. комментарии) НЕ регистрируйте контейнер Unity внутри себя, это вызовет StackOverflowException в container.Dispose(), правильный экземпляр будет внедрен как зависимость без регистрации.

person Max Galkin    schedule 13.09.2010
comment
Спасибо за эту информацию. Этим утром я долго пытался заставить автоматические фабрики работать, пока не обнаружил, что Unity не может внедрить фабрики, когда у зависимости есть конструктор с параметрами, что делает все это пустой тратой времени. Вы не можете использовать DI, если ваши зависимости также используют DI. Я думаю, что я собираюсь отказаться от Unity, у меня с самого начала не было ничего, кроме проблем, и его почти невозможно отлаживать. Каждое незначительное изменение в моей архитектуре требует дней, чтобы начать работать :( - person fearofawhackplanet; 14.09.2010
comment
Уверены ли вы? Я думал, что Func‹T› просто оборачивает вызов container.Resolve‹T›... странно... - person Max Galkin; 14.09.2010
comment
Не знаю... У меня не было особых проблем с Unity... Мои коллеги используют Autofac, и я слышал о нем хорошие отзывы, может, вам стоит попробовать. - person Max Galkin; 14.09.2010
comment
Контейнер автоматически регистрируется сам с собой. Все, что вы получаете, вызывая container.RegisterInstance›(container), — это переполнение стека при выполнении container.Dispose(). - person Chris Tavares; 15.09.2010
comment
@Chris: ты прав... Я обновлю ответ. Большое спасибо! - person Max Galkin; 15.09.2010