Losing RegionAdapter mappings using Microsoft.DI extensions...
horseyhorsey opened this issue · 10 comments
We can get constructor injection working with the following.
protected override IContainerExtension CreateContainerExtension() => PrismContainerExtension.Init();
protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
containerRegistry = containerRegistry.RegisterServices(svc =>
{
MyApplication.DependencyInjection.AddApplication(svc);
});
}
The IRegionAdapter for the type System.Windows.Controls.ContentControl is not registered
Prism.Regions.UpdateRegionsException: 'An exception occurred while trying to create region objects.
- The most likely causing exception was: '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 'SidePanelRegion'. 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.
at Prism.Regions.RegionAdapterMappings.GetMapping(Type controlType)
at Prism.Regions.Behaviors.DelayedRegionCreationBehavior.CreateRegion(DependencyObject targetElement, String regionName).
---> 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.
at Prism.Regions.RegionAdapterMappings.GetMapping(Type controlType)
at Prism.Regions.Behaviors.DelayedRegionCreationBehavior.CreateRegion(DependencyObject targetElement, String regionName)
--- End of inner exception stack trace ---
at Prism.Regions.Behaviors.DelayedRegionCreationBehavior.CreateRegion(DependencyObject targetElement, String regionName)
at Prism.Regions.Behaviors.DelayedRegionCreationBehavior.TryCreateRegion()
at Prism.Regions.Behaviors.DelayedRegionCreationBehavior.OnUpdatingRegions(Object sender, EventArgs e)
--- End of inner exception stack trace ---
at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor, Boolean wrapExceptions)
at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at System.Delegate.DynamicInvokeImpl(Object[] args)
at Prism.Events.WeakDelegatesManager.Raise(Object[] args)
at Prism.Regions.RegionManager.UpdateRegions()'.
But also check the InnerExceptions for more detail or call .GetRootException(). '
After overriding the ConfigureRegionAdapterMappings
we can see the mappings there after invoking the base method.
Not sure where these get lost? The app works as it should using Unity.
You may want to refer to the ReadMe for more contextual information here.
I have no real plans at this point of doing anything with that container. If you or someone else would like to step up and help work the bugs out of it and maintain it, I'm happy to take those community PRs.
No problem. The region adpaters don't work after explictly adding them either. WPF will have to register the service with Unity instead.
I found the problem:
PrismContainerExtension
awlays creates the newInstance
ifRegister
was called before.- If you use
RegisterSingleton<>
in one IServiceCollection and then create twoIServiceProvider
based on it - they will have different references on singleton. ConcreteAwareServiceProvider.GetConcreteImplementation
usesPrismContainerExtension.Current.Register
, which force recreatePrismContainerExtension.Instance
.PrismApplicationBase.ConfigureRegionAdapterMappings
calls for one instance ofRegionAdapterMappings
, but after we create new instance of this class, which doesn't have any mappings.
But I don't know the best way to fix it.
There's only one way I can think of. Remove the package dependency on Microsoft.Extensions.DependencyInjection... target the abstractions only and bring the Microsoft code in directly so we can make the modifications needed.
I alos have this trouble in my wpf application,Can you tell me how to fix it. Tks!
IF you can provider a demo for use Prism.Microsoft.DependencyInjection ,that would be very useful.
@hippieZhou, it seems to me, that it doesn't work at all. Probably, it's better to use another container.
As I've noted in the very package description that is an Experimental Container. I've left this issue open for anyone who would like to try to tackle it. But I have no plans of any serious development around that container.
I found the problem:
PrismContainerExtension
awlays creates the newInstance
ifRegister
was called before.- If you use
RegisterSingleton<>
in one IServiceCollection and then create twoIServiceProvider
based on it - they will have different references on singleton.ConcreteAwareServiceProvider.GetConcreteImplementation
usesPrismContainerExtension.Current.Register
, which force recreatePrismContainerExtension.Instance
.PrismApplicationBase.ConfigureRegionAdapterMappings
calls for one instance ofRegionAdapterMappings
, but after we create new instance of this class, which doesn't have any mappings.But I don't know the best way to fix it.
Did you find a solution?
Did you find a solution?
We use another container. We only use IServiceCollectionExtensions
from this package which allows using shared DI code (extensions written for this IContainerRegistry containerRegistry
).
Instead of using this package, since it doesn't work...,
I just wrote some static functions, where I can register services...
Basicly I make use of the generic container to register the services, and then I copy them over to prism container.
public static void RegisterServices(this IContainerRegistry containerRegistry)
{
IServiceCollection serviceCollection = null;
IHost appHost = Host.CreateDefaultBuilder().ConfigureServices((hostContext, services) =>
{
services.ConfigureServices();
serviceCollection = services;
}).Build();
RegisterServices(containerRegistry, serviceCollection, appHost.Services);
}
private static void RegisterServices(IContainerRegistry containerRegistry, IServiceCollection services, IServiceProvider serviceProvider)
{
foreach (ServiceDescriptor service in services)
{
switch (service.Lifetime)
{
case ServiceLifetime.Singleton:
if (service.ImplementationType != null)
{
containerRegistry.RegisterSingleton(service.ServiceType, service.ImplementationType);
}
else if (service.ImplementationInstance != null)
{
containerRegistry.RegisterInstance(service.ServiceType, service.ImplementationInstance);
}
else if (service.ImplementationFactory != null)
{
containerRegistry.RegisterSingleton(service.ServiceType, () => service.ImplementationFactory(serviceProvider));
}
break;
case ServiceLifetime.Scoped:
if (service.ImplementationType != null)
{
containerRegistry.RegisterScoped(service.ServiceType, service.ImplementationType);
}
else if (service.ImplementationFactory != null)
{
containerRegistry.RegisterScoped(service.ServiceType, () => service.ImplementationFactory(serviceProvider));
}
else
{
containerRegistry.RegisterScoped(service.ServiceType);
}
break;
case ServiceLifetime.Transient:
if (service.ImplementationType != null)
{
containerRegistry.Register(service.ServiceType, service.ImplementationType);
}
else if (service.ImplementationFactory != null)
{
containerRegistry.Register(service.ServiceType, () => service.ImplementationFactory(serviceProvider));
}
break;
default:
break;
}
}
}
public static void ConfigureServices(this IServiceCollection services)
{
//add here your services
services.AddHttpClient();
}
Followed by using it in app.xaml.cs ...
protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
containerRegistry.RegisterServices();
}