Reputation: 9638
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>();
}
Upvotes: 0
Views: 324
Reputation: 9638
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 :).
Upvotes: 1