I’m using Prism.DryIoc 7.1.0.431 in my WPF application (.NET 4.7.2) and switched from using a Bootstrapper to PrismApplication (Prism.DryIoc. PrismApplication).
My App class overwrites the _RegisterTypes_ method and registers some types with the following code:
var container = containerRegistry.GetContainer();
container.Register<IView, ViewA>( );
container.Register<IView, ViewB>( );
When resolving all _IView_ implementations (_container.ResolveMany
The cause of this behavior is the configuration of the DryIoC container.
The _Prism.DryIoc.PrismApplication_ class creates the container with the rule “IfAlreadyRegistered.Replace”.
protected virtual Rules CreateContainerRules()
=> Rules.Default.WithAutoConcreteTypeResolution()
.With(Made.Of(FactoryMethod.ConstructorWithResolvableArguments))
.WithDefaultIfAlreadyRegistered(IfAlreadyRegistered.Replace);
Removing this rule allows the registration of multiple implementations.
Create a Prism application using DryIoC as DI framework.
Register multiple implementations of an interface and try to resolve all the implementations using _container.ResolveMany_ or _container.Resolve< IEnumerable
Resolve should return all registered implementations.
WithDefaultIfAlreadyRegistered(IfAlreadyRegistered.Replace) should not be part the default rule.
Changing the Rules as follows would make the registration work as expected:
protected virtual Rules CreateContainerRules()
=> Rules.Default.WithAutoConcreteTypeResolution()
.With(Made.Of(FactoryMethod.ConstructorWithResolvableArguments));
Registering an implementation replaces all previous registrations with the same to-type.
This is by design. If you do not like the current rules, you must change them by overriding the CreateContainerRules method and provide your own rules.
@DaveSenn consider that Prism has to register a number of base implementations such as an effectively null implementation of ILoggerFacade. If we simply added a registration rather than replacing it, you would not get your own implementation which would be a poor design choice. You do have access to the container through the GetContainer() extension method, or as @brianlagunas suggested you could create your own rules, but know you do so at your own risk.
I'd like to get some quick clarification on this. I just upgraded my Prism framework to 7.1 with DryIoc.
Previously, on boot, my container gets multiple instances of, for example, "IConnectionProvider" which is dynamic based on the number of hardware devices that are physically connected to the system. On boot various modules would register their own IConnectionProvider with the container.
With Unity I was able to easily able resolve multiple instances with:
List< IConnectionProvider > connectionProviders = Container.ResolveAll< IConnectionProvider >().ToList();
So it sounds like this sort of pattern has been removed in Prism 7x?
If so would you instead suggest I just make a dedicated service for this? For example, by registering a single ConnectionProviderService to interact with the collection in a structured fashion, instead of using the container directly?
Advice would be much appreciated here. Thanks!
@andygikling you still have access to the container. So you can do whatever you want.
@brianlagunas, thanks for the followup - I'm a huge fan of you and Dan's work! Keep killing it!
Right understood, but would you say it's better make new DryIoc Rules as described above, or go the Service route I described? @DaveSenn's comment:
you could create your own rules, but know you do so at your own risk.
makes me think that option is going to have consequences and pitfalls I'm not foreseeing.
Thanks for your time.
@andygikling The best advice I can give is to do what works for you.
Well, frankly, there are many things that _would_ work for me boss. For example, not migrating to Prism 7 and dealing with all the breaking changes in the library would have worked fine lol...
Well.... you could always revert and not worry about it :)
hahaha right... Tell ya what, I'll write a long dissertation on the issue once I understand it better and I'll follow up here with advice for the next guy.
I'm sure the community would appreciate that.
In my project I couldn't change the rules so I used
container.RegisterMany<ViewA>(ifAlreadyRegistered:IfAlreadyRegistered.AppendNewImplementation);
container.RegisterMany<ViewB>(ifAlreadyRegistered: IfAlreadyRegistered.AppendNewImplementation);
RegisterMany registers all of the public implemented interfaces.
This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.
Most helpful comment
I'm sure the community would appreciate that.