6

I've been researching all morning trying to find best practices for accessing your IoC. After adding constructor injection to your classes you still need to access the contianer from classes that might be deep in your applications object graph. In my case I'm doing MVVM in WPF and some of my View Models need to create other View Models and they would use the container to do so. But the question is where to do they get the container from. Does it make sense to inject it and pass it around? Is it ok to make it an injectable singleton? Is a factory that serves up a singleton more appropraite?

What's are the options and tradeoffs?

Update

I found this great talk by Matt Hinze that covers a lot of IoC ground: http://www.drowningintechnicaldebt.com/ShawnWeisfeld/archive/2010/04/08/inversion-of-control-in-action-by-matt-hinze-north.aspx

Looks like one answer is to use the scanning feature and store the IoC configurations in registries in each assembly and then during scaning those registry configurations will be added.

Are there other approaches to consider? Especially considering that Matt demonstrated using the ServiceLocator pattern while Mark Seeman calls this an anti-pattern. Note that Matt cautioned against over using the pattern and that Mark's definition of the Service Locator (http://blog.ploeh.dk/Trackback.aspx?guid=5f05c086-295b-41e5-a50a-ed0cd77ac4bd) seems different than what Matt demonstrated.

Ryan Vice
  • 2,133
  • 3
  • 23
  • 33
  • 2
    Passing the container around tends to lead to the service locator anti-pattern (well some people consider it an anti-pattern). http://blog.ploeh.dk/2010/02/03/ServiceLocatorIsAnAntiPattern.aspx – Jason Down Dec 04 '11 at 14:38
  • Good point - "some people". The discussion however has arguments for both sides and is far beyond this question. – Wiktor Zychla Dec 04 '11 at 14:45
  • @JasonDown: So then how do you avoid the anti-pattern. That's the meat of the question I'm asking. What's a good best practice or pattern for making your IoC available to classes that need it? – Ryan Vice Dec 04 '11 at 16:29
  • 3
    Related/partial answer: http://stackoverflow.com/questions/2386487/is-it-better-to-create-a-singleton-to-access-unity-container-or-pass-it-through – Mark Seemann Dec 04 '11 at 22:15
  • 3
    Paired with the above link, this contains the missing pieces of the puzzle: http://stackoverflow.com/questions/1943576/is-there-a-pattern-for-initializing-objects-created-via-a-di-container – Mark Seemann Dec 04 '11 at 22:16
  • @MarkSeemann: Thanks for the response Mark. I just ordered your book so definitely appreciate you taking the time to help me here. The problem I am having though is figuring out the best approach to accessing my IoC container from deep in my object graph at run time. The approach I've seen used is to use service locator to return an interface that wraps your IoC but I know you call ServiceLocator an anti-pattern and wanted to know what the better approach to this is. – Ryan Vice Dec 04 '11 at 23:53
  • 3
    Use an Abstract Factory as described in the above link. It's not the same as a Service Locator: http://blog.ploeh.dk/2010/11/01/PatternRecognitionAbstractFactoryOrServiceLocator.aspx – Mark Seemann Dec 05 '11 at 06:29
  • @MarkSeemann: Thanks again Mark but how do you get an instance of the AbstractFactory in the class that needs it if it's deep in your object graph? Do you pass it down using poor man's DI? If you new it up then you are coupled to the implementation and make testing difficult. – Ryan Vice Dec 07 '11 at 15:52
  • Inject the Abstract Factory through the constructor. It's no different from any other dependency. – Mark Seemann Dec 07 '11 at 18:01
  • @MarkSeemann Hi Mark, I wanted to clarify the assumptions I'm now working under. (1) I only allow my composite root and my abstract factories to access the IoC contianer (2) Each classes constructor only takes what it needs and nothing is passed through (3) construction requiring runtime values is done via factories which internally use IoC for object creation and resolving dependencies. – Ryan Vice Jan 02 '12 at 16:58
  • Sounds about right if you implement the factories in the same library as the rest of your Composition Root. If so, you have very effectively shielded the rest of the app from the container. – Mark Seemann Jan 02 '12 at 20:38

2 Answers2

2

Instead of injecting your actual ViewModel instances, which will be hard, as you say, you could inject factories to your top ViewModels. It's kind of like the service locator pattern, expect the factories (or services providers, or what have you) will be more specific in what they can deliver.

lbergnehr
  • 1,578
  • 11
  • 15
  • 1
    But isn't that just moving the problem because then the question would become how do the lower down VMs access the factories. I assumed a key benifit of IoC is that you can avoid having unnecessary dependencies because classes use the IoC to resolve the dependencies of classe that they need to create. – Ryan Vice Dec 04 '11 at 16:26
  • That's very true, you would indeed have to pass you constructor arguments manually in order to use it this way. – lbergnehr Dec 04 '11 at 17:16
  • 1
    Several IoC container frameworks will resolve factory delegates (generic Func). See for example Unity's automatic factories. An alternative is to inject an interface to your factory. – TrueWill Dec 05 '11 at 14:13
0

One of the ways is to use a ServiceLocator pointing to a specific container. Since the locator is usually exposed as a singleton, you get your container for free from any place in the code.

For example, in Unity it would be like

// configure the locator somewhere early
UnityServiceLocator locator = new UnityServiceLocator( container );                 
ServiceLocator.SetLocatorProvider( () => locator );

...

// get the container anywhere
var container = ServiceLocator.Current.GetInstance<IUnityContainer>();

The discussion whether or not the locator is an antipattern is beyond the scope. In my opinion - it is not, at least not more "antipattern" than the whole IoC.

Wiktor Zychla
  • 47,367
  • 6
  • 74
  • 106
  • Thanks Wiktor. If you were doing this with fluent configurations then where would your service locator live? The problem I ran into with this approach is that the UnityServiceLocator would need to reference all assemblies but then all assemblies would need to reference the UnityServiceLocator for creating class intances. – Ryan Vice Dec 04 '11 at 16:32
  • If I understand correctly then yes, all project assemblies must reference Unity but this would be true for any IoC framework. However, "UnityServiceLocator would need to reference all assemblies" is not clear and I don't think it's necessary. Fluent configuration doesn't probably change this. – Wiktor Zychla Dec 04 '11 at 16:45
  • With unity and XML configurations I'd agree but I'm using Ninject with Fluent and so to be able to map an interface to a class you have to have references to both where you create the configuration. – Ryan Vice Dec 04 '11 at 18:57
  • Are you sure? Especially when you are configuring declaratively (with XML), you shouldn't have to reference anything as you provide full type names in the XML. – Wiktor Zychla Dec 04 '11 at 20:04
  • Correct but I'm using fluent configurations. – Ryan Vice Dec 04 '11 at 21:08
  • Right. I hope it doesn't change the fact that the service locator is a viable solution. All your libraries reference the library containing the service locator class (the IoC implementation) and your main module contains references to all of your libraries as well as the locator. There's no problem there. – Wiktor Zychla Dec 04 '11 at 21:21