简体   繁体   中英

Creating a LightInject Bootstrapper for Prism, missing registration of region adapters

I'm trying to create a LightInject bootstrapper for Prism, I've copied the code of the NinjectBootstrapper ( source ) and replaced Ninject's IKernel with LightInject's IServiceContainer . I've also created and registered a LightInjectServiceLocatorAdapter ( Ninject version ).

The registration and service locator adapter are working. I see that the class RegionAdapterMappings is successfully retrieved from the service locator.

In the ConfigureRegionAdapterMappings step of the bootstrapper an instance of the class SelectorRegionAdapter is requested from the service locator. This fails. The class was never registered. I can't find any reference to it in the NinjectBootstrapper . So how is this class retrieved by the Ninject bootstrapper?

I've tried registering the class manually (and a few more region adapters and the DelayedRegionCreationBehavior ) but then Prism fails with an UpdateRegionsException

System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> Prism.Regions.Behaviors.RegionCreationException: An exception occurred while creating a region with name 'Menu'. The exception was: System.Collections.Generic.KeyNotFoundException: The IRegionAdapter for the type System.Windows.Controls.ContentControl is not registered in the region adapter mappings. You can register an IRegionAdapter for this control by overriding the ConfigureRegionAdapterMappings method in the bootstrapper.

I can't find any source dealing with creating adding your own DI container and I have no idea what step I am missing. What am I doing wrong?

I configure my ServiceContainer like this (the Ninject equivalent is the ConfigureKernel method).

protected virtual void ConfigureServiceContainer()
{
    this.ServiceContainer.RegisterInstance<IServiceContainer>(this.ServiceContainer);
    this.ServiceContainer.RegisterInstance(this.Logger);
    this.ServiceContainer.RegisterInstance(this.ModuleCatalog);

    if (!this.useDefaultConfiguration)
        return;

    this.ServiceContainer.Register<IServiceLocator, LightInjectServiceLocatorAdapter>();
    this.ServiceContainer.Register<IModuleInitializer, ModuleInitializer>();
    this.ServiceContainer.Register<IModuleManager, ModuleManager>();

    this.ServiceContainer.Register<RegionAdapterMappings, RegionAdapterMappings>();

    // The following 4 registrations are not in the NinjectBootstrapper
    this.ServiceContainer.Register<SelectorRegionAdapter, SelectorRegionAdapter>();
    this.ServiceContainer.Register<ItemsControlRegionAdapter, ItemsControlRegionAdapter>();
    this.ServiceContainer.Register<ContentControlRegionAdapter, ContentControlRegionAdapter>();
    this.ServiceContainer.Register<DelayedRegionCreationBehavior, DelayedRegionCreationBehavior>();

    this.ServiceContainer.Register<IRegionManager, RegionManager>();
    this.ServiceContainer.Register<IEventAggregator, EventAggregator>();
    this.ServiceContainer.Register<IRegionViewRegistry, RegionViewRegistry>();
    this.ServiceContainer.Register<IRegionBehaviorFactory, RegionBehaviorFactory>();
    this.ServiceContainer.Register<IRegionNavigationJournalEntry, RegionNavigationJournalEntry>();
    this.ServiceContainer.Register<IRegionNavigationJournal, RegionNavigationJournal>();
    this.ServiceContainer.Register<IRegionNavigationService, RegionNavigationService>();
    this.ServiceContainer.Register<IRegionNavigationContentLoader, RegionNavigationContentLoader>();
}

Turns out there were two things that I did wrong.

For the registration in ConfigureServiceContainer the Ninject bootstrapper uses an extension method public static void RegisterTypeIfMissing<A, B>(this IServiceContainer container, bool singletonScope) that registers some of the dependencies in singleton scope.

The other thing I didn't understand is that Ninject will happily resolve any concrete type even if it isn't registered. LightInject does not. I finally solved this by registering all the concrete classes from Prism.WPF that end in "Behavior" or "Adapter" to themselves like this:

// Register all concrete adapters and behaviors in the Prism.WPF assembly
var wpfAssembly = typeof (SelectorRegionAdapter).Assembly;
this.ServiceContainer.RegisterAssembly(wpfAssembly, (t0, t1) => t0.Name.EndsWith("Adapter") || t0.Name.EndsWith("Behavior"));

Finally I had to ditch all the Module management from Prism. LightInject expects a single class that extends from ICompositionRoot to be present in an assembly and will load types happily from there. This works fine for my approach :).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM