I have an interface INavigationService and a simple container that allows registration with and without key.
This is useful to me as the framework will inject the registered instances into the constructor of my view models.
Now I have multiple navigation services (due to frames in my UI). They all implement the same basic interface (INavigationService).
I want to be able to have the container inject these instances into the correct navigation tree (frame + subsequent views/view models) without me having to pass around parameters (DI registration key).
How is this usually done?
I can imagine something that is attribute based (thus putting the registration key onto all dependent class definitions). But the container doesn’t support this. It also seems to be a hassle.
I could also create an interface exclusively for tagging. So INavigationService<T> and register each navigation service with a different type argument. E.g. the type of the first view of a frame. This would give me the resolution I need, although I would pass around interfaces that do not have any meaning.
On the other hand, I get IDE support for finding dependent views (for example by creating types like FileTreeNavigation : INavigationService<FileTreeView>
Is there another pattern?
I’m not sure how this applies to Caliburn Micro, but since the question is about patterns, I’ll describe here the way I managed to solve this problem with StrucureMap: using the
Ctor<>method which allows specifying concrete types for constructor parameter resolution.Also, I think using specialized interfaces (your
FileTreeNavigationexample) is great, but if for some reason you don’t find this appropriate, read on.Let’s suppose that we have the
INavigationServiceinterface and two different implementations:Next, we have two different Service classes, both depending on the
INavigationServiceinterface:Finally, we have a class that we’ll resolve using the IoC container. The class depends on both
ServiceAandServiceBand is defined as follows:StructureMap offers the possibility of specifying what type to use in order to resolve a constructor parameter. This is how the registration looks like:
Now, when I call
container.GetInstance<SomeClassToResolve>();it’ll construct an instance ofSomeClassToResolve, which has instances ofServiceAandServiceBcorrectly constructed (havingNavigationServiceAandNavigationServiceB, respectively).This is one way to do it, that I found to be more straight forward. There’s also the possibility of doing Conditional Construction, but I think that can get pretty complex.
PS: searching for “caliburn micro constructor” I stumbled upon this approach which seems similar to what I’m doing with StructureMap (only that here it’s called
InjectionConstructor).