3

I'm working with the Prism Library WPF Samples here (specifically, this one).

I'm trying to convert the sample's bootstrapper from using the Unity container to DryIoc. The original code looks like this:

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));
    }
}

My new code looks like this:

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));
    }
}

But when I try to run the new code, I get the following exception:

enter image description here

The Inner Exception says:

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

And the Inner Exception of that Exception says:

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.

Code for 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>();
    }
}
Robert Harvey
  • 178,213
  • 47
  • 333
  • 501
  • What do you inject into `ModuleAModule`? `IContainer` or a concrete type? Looks like you're trying to create a new container instead of using the existing one. – Haukinger Mar 30 '18 at 20:05
  • Edited to add the code for `ModuleAModule`. The code for the entire sample (which is still pretty small) can be found [here](https://github.com/PrismLibrary/Prism-Samples-Wpf/tree/master/21-PassingParameters), which might be easier to look through. – Robert Harvey Mar 30 '18 at 20:10
  • You need to pass `IContainer` to constructor of module, not `Container`. – Evk Mar 30 '18 at 20:11
  • Yep, that fixed the problem. If you post an answer, I'll accept. The navigation doesn't work, but that appears to be a different problem. – Robert Harvey Mar 30 '18 at 20:14

1 Answers1

6

Instead of passing concrete Container type to module constructor - you need to pass IContainer:

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

This will fix your issue, but navigation will not work. To fix navigation - you need to do the same with RegionManager, that is: pass IRegionManager and not concrete type:

public ModuleAModule(IRegionManager regionManager, IContainer container)

Not only in module itself, but in other places, such as in PersonListViewModel:

public PersonListViewModel(IRegionManager regionManager)

Passing concrete implementations is not a good practice in general, and here it breaks on multiple levels with DryIoc. That's because both Container and RegionManager, as concrete types, are not registered in DryIoc container (only interfaces). But when you try to resolve unregistered type, DryIoc, instead of throwing exception, will try to create instance of this type (and resolve its dependencies if any).

With Container that creation just fails. With RegionManager it succeeds but problem is every resolution creates new instance of RegionManager (while IRegionManager interface is registered as singleton). So your module, your PersonListViewModel etc all have different region manager instances, so navigation breaks.

Evk
  • 98,527
  • 8
  • 141
  • 191
  • This seems like a much better arrangement than the Unity configuration. Unity actually breaks if the interfaces are used. – Robert Harvey Mar 30 '18 at 20:30
  • @RobertHarvey I've added a bit of explanation about the reasons of this behavior. – Evk Mar 30 '18 at 20:33
  • Navigation still doesn't work, but it's not due to the types anymore. They're being instantiated properly in `ModuleAModule`'s constructor, so the problem must be somewhere else, perhaps in the `RegisterViewWithRegion` method. – Robert Harvey Mar 30 '18 at 20:47
  • @RobertHarvey that's strange, because I downloaded that project and verified navigation works after mentioned changes (in `ModuleAModule` AND `PersonListViewModel`, because in `PersonListViewModel` region manager is also passed with concrete type). – Evk Mar 30 '18 at 20:50
  • Changed to `IRegionManager` in `PersonListViewModel` and navigation now works. You're a stud. And I now understand navigation in Prism a lot better than I did before. – Robert Harvey Mar 30 '18 at 20:53