Dependency InjectionSeparating the Container
In a previous post, I made the statement that I believe that using an IoC container should be transparent to the application code, and that a good IoC can and should be invisible to anything but the Main() method.
I would like to expand a bit on this topic, cover the sample problem that Tobias had brought up:
I never could achieve this and I'm wondering, what you mean by this statement. There a are always a lot of references to the DI/IoC container throughout the application. E.g. each IView that needs to be created to show a WinForm requires to ask the Container to give me the instances:
ObjectFactory.GetInstance<IMyView>()
It might be an IController as well and IView is automatically resolved by the container, but as long as I need to instantiate new objects dynamically, I need to reference the IoC container at serveral places outside Main(). Maybe in very simple cases, the whole object tree required during the lifecycle of the application can be set up in Main().
Tobias has indeed hit the nail on the head, lifecycle issues are the one thing that can cause a lot of issues there. I would preface this by saying that I do not always follow this advice fully, and I have no compunctions about using the IoC as a service locator where appropriate, but I would try to limit it to the infrastructure part of the application only.
In this scenario, what I would generally do is define something like this:
// infrastructure service public interface IRedirectionService { IRedirectionOperation To<TController>(); }
And then use it like this:
Redirection .To<OrderController>() .ActivateAndWait();
It depends on the given scenario, but in this case, I am handing control from one controller to the other, and waiting until the second controller is done doing its job (think about it like modal dialog).
The Redirection Service is responsible for creating the controller / view (or find them if they are already active), and activate them.
IoC & DI are under the cover, but I don't have it in my face, and I have nice API against which I can work.
More posts in "Dependency Injection" series:
- (23 Aug 2007) Separating the Container
- (21 Aug 2007) Applicability, Benefits and Mocking
- (18 Aug 2007) IAmDonQuixote ?
- (18 Aug 2007) More than a testing seam
Comments
ObjectFactory.GetInstance<IMyView>()
That's awesome code. Truly inspired code. I've been kicking myself for close to 3 years now about "ObjectFactory" since every framework under the sun has an "ObjectFactory" class.
I'm doing similar things now to register Command classes with TreeNode's like this:
StructureMap is under the covers to hook up everything the concrete Command classes need in their constructors, but it's hidden in this usage.
This is a very nice looking API for the controller redirection, Thanks so much. I suspect I'll be able to move some code out of the application level and into infrastructure just as you suggest.
However, is there any source for a more fleshed-out example of this? Not looking for you to make a blog post out of it, but any links to source examples you know of that use something like this would be really really helpful. Thanks again
Thanks for picking this up from my comments. Moving/Hiding the calls to the IoC container solely into infrastructure code is something I haven't considered yet. I've always treated the DI container as part of my infrastructure, so "ObjectFactory.GetInstance<OrderController>().Activate()" doesn't look that much different than "Redirection.To<OrderController>().ActivateAndWait()" at the first sight. The latter improves the readability and might be the better way in the longer run. I have to try this out and see how far I get.
@Jeremy: Stop kicking yourself, "ObjectFactory" perfectly describes, what StructureMap does. I think "Container" is worse. I expect a container to be something I can put things in, move it around and get the things out of it again.
How do you deal with releasing components with out exposing the container?
Adam,
There are few options here.
The first is not dealing with that and letting the GC handle it. That is my most used option.
The other option is to add a Release() method to the Redirection service (or similar)
The final option is to use Dispose(), and supply an interceptor that would release the component from the container after dispose was called.
Comment preview