Как настроить каталог модулей в Prism, используя DryIoc вместо Unity?

Я работаю с примерами WPF библиотеки Prism здесь (в частности, вот этот).

Я пытаюсь преобразовать загрузчик примера из контейнера Unity в DryIoc. Исходный код выглядит так:

class Bootstrapper : UnityBootstrapper
{
    protected override DependencyObject CreateShell()
    {
        return Container.Resolve<MainWindow>();
    }

    protected override void InitializeShell()
    {
        Application.Current.MainWindow.Show();
    }

    protected override void ConfigureModuleCatalog()
    {
        var catalog = (ModuleCatalog)ModuleCatalog;
        catalog.AddModule(typeof(ModuleAModule));
    }
}

Мой новый код выглядит так:

class Bootstrapper : DryIocBootstrapper
{
    protected override DependencyObject CreateShell()
    {
        return Container.Resolve(typeof(MainWindow), true) as DependencyObject;
    }

    protected override void InitializeShell()
    {
        Application.Current.MainWindow.Show();
    }

    protected override void ConfigureModuleCatalog()
    {
        var catalog = (ModuleCatalog)ModuleCatalog;
        catalog.AddModule(typeof(ModuleAModule));
    }
}

Но когда я пытаюсь запустить новый код, я получаю следующее исключение:

введите здесь описание изображения

Внутреннее исключение говорит:

Activation error occurred while trying to get instance of type ModuleAModule, key ""

И внутреннее исключение этого исключения говорит:

Unable to get constructor of DryIoc.Rules using provided constructor selector when resolving DryIoc.Rules {ReturnDefault} as parameter "rules"
  in DryIoc.Container as parameter "container"
  in ModuleA.ModuleAModule.

Код для модуляМодуль:

public class ModuleAModule : IModule
{
    IRegionManager _regionManager;
    Container _container;

    public ModuleAModule(RegionManager regionManager, Container container)
    {
        _regionManager = regionManager;
        _container = container;
    }

    public void Initialize()
    {
        _regionManager.RegisterViewWithRegion("ContentRegion", typeof(PersonList));

        _container.RegisterTypeForNavigation<PersonDetail>();
    }
}

person Robert Harvey    schedule 30.03.2018    source источник
comment
Что вы вводите в ModuleAModule? IContainer или конкретный тип? Похоже, вы пытаетесь создать новый контейнер вместо того, чтобы использовать существующий.   -  person Haukinger    schedule 30.03.2018
comment
Отредактировано, чтобы добавить код для ModuleAModule. Код для всего примера (который все еще довольно мал) можно найти здесь, что может быть проще просмотреть.   -  person Robert Harvey    schedule 30.03.2018
comment
Вам нужно передать IContainer в конструктор модуля, а не Container.   -  person Evk    schedule 30.03.2018
comment
Да, это решило проблему. Если вы опубликуете ответ, я приму. Навигация не работает, но это другая проблема.   -  person Robert Harvey    schedule 30.03.2018


Ответы (1)


Вместо того, чтобы передавать конкретный тип Container в конструктор модуля, вам нужно передать IContainer:

public ModuleAModule(RegionManager regionManager, IContainer container)
{
    _regionManager = regionManager;
    _container = container;
}

Это решит вашу проблему, но навигация работать не будет. Чтобы исправить навигацию - нужно сделать то же самое с RegionManager, то есть: передать IRegionManager а не конкретный тип:

public ModuleAModule(IRegionManager regionManager, IContainer container)

Не только в самом модуле, но и в других местах, например, в PersonListViewModel:

public PersonListViewModel(IRegionManager regionManager)

Передача конкретных реализаций в целом не является хорошей практикой, и здесь она ломается на нескольких уровнях с DryIoc. Это потому, что Container и RegionManager как конкретные типы не зарегистрированы в контейнере DryIoc (только интерфейсы). Но когда вы пытаетесь разрешить незарегистрированный тип, DryIoc вместо того, чтобы генерировать исключение, попытается создать экземпляр этого типа (и разрешить его зависимости, если таковые имеются).

С Container это творение просто терпит неудачу. С RegionManager это удается, но проблема в том, что каждое разрешение создает новый экземпляр RegionManager (в то время как интерфейс IRegionManager регистрируется как синглтон). Таким образом, ваш модуль, ваш PersonListViewModel и т. д. имеют разные экземпляры диспетчера регионов, поэтому навигация прерывается.

person Evk    schedule 30.03.2018
comment
Это кажется гораздо лучшей конфигурацией, чем конфигурация Unity. Unity фактически ломается, если используются интерфейсы. - person Robert Harvey; 30.03.2018
comment
@RobertHarvey Я добавил небольшое объяснение причин такого поведения. - person Evk; 30.03.2018
comment
Навигация по-прежнему не работает, но это уже не из-за типов. Они правильно создаются в конструкторе ModuleAModule, поэтому проблема должна быть где-то еще, возможно, в методе RegisterViewWithRegion. - person Robert Harvey; 30.03.2018
comment
@RobertHarvey, это странно, потому что я скачал этот проект и проверил, что навигация работает после упомянутых изменений (в ModuleAModule И PersonListViewModel, потому что в PersonListViewModel региональный менеджер также передается с конкретным типом). - person Evk; 30.03.2018
comment
Изменено на IRegionManager в PersonListViewModel, теперь навигация работает. Ты шпилька. И теперь я понимаю навигацию в Prism намного лучше, чем раньше. - person Robert Harvey; 30.03.2018