Given the example dependency tree below I would like to select the bottom level Config
instance based on the top level dependency being resolved from the container e.g. TopLevelMessageConsumer
would resolve the same IMessageService
& IMessageQueue
implementations as TopLevelMessageDispatcher
but each would have their own Config
instance.
- TopLevelMessageConsumer
- IMessageService
- IMessageQueue
- Config
- TopLevelMessageDispatcher
- IMessageService
- IMessageQueue
- Config
I know this is possible using Keyed
or Named
but this requires each dependency in the tree to be registered n times varying by the number of config variations. Resulting in:
containerBuilder.RegisterInstance(config1).Keyed<Config>(Key.One).SingleInstance();
containerBuilder.RegisterInstance(config2).Keyed<Config>(Key.Two).SingleInstance();
containerBuilder.RegisterType<MessageQueue>().Keyed<IMessageQueue>(Key.One).SingleInstance()
.WithParameter(ResolvedParameter.ForKeyed<Config>(Key.One));
containerBuilder.RegisterType<MessageQueue>().Keyed<IMessageQueue>(Key.Two).SingleInstance()
.WithParameter(ResolvedParameter.ForKeyed<Config>(Key.Two));
containerBuilder.RegisterType<MessageService>().Keyed<IMessageService>(Key.One).SingleInstance()
.WithParameter(ResolvedParameter.ForKeyed<IMessageQueue>(Key.One));
containerBuilder.RegisterType<MessageService>().Keyed<IMessageService>(Key.Two).SingleInstance()
.WithParameter(ResolvedParameter.ForKeyed<IMessageQueue>(Key.Two));
containerBuilder.RegisterType<TopLevelMessageConsumer>().AsSelf().SingleInstance()
.WithParameter(ResolvedParameter.ForKeyed<IMessageService>(Key.One));
containerBuilder.RegisterType<TopLevelMessageDispatcher>().AsSelf().SingleInstance()
.WithParameter(ResolvedParameter.ForKeyed<IMessageService>(Key.Two));
Is there a better/cleaner way to register them?
You can simplify this greatly by using generic interfaces instead of explicit DI registration. The only condition is that you need to use some sort of type to differentiate between the services. In this case, making separate configuration classes would be a natural fit.
Config
Interfaces
Services
Usage
Note that the implementation of the services don't necessarily need to worry about the fact the type is generic - the only thing that needs to change is the constructor signature to make a more explicit call for the generic type.