5
\$\begingroup\$

I'm wondering what people think about Dependency Injection vs Service Locator patterns. Specifically I'm using Prism with MEF. I'm also using the MVVM pattern.

So I have a service which I export. I also have a class which doesn't export its class type as I don't need that to be registered with MEF. This class is actually a View-Model which is assigned to a hierarchical data template inside a TreeView.

However the view-model needs to import an interface registered with MEF.

Now I have three possible ways to do this:

  1. Set an [Import] on the interface and use ComposeParts in the constructor to inject the dependency.
  2. Use SerivceLocator.Current pattern to get the instance of the service.
  3. Pass in the service interface on the constructor, which is kind of a manual dependency injection.

Here some example code to demonstrate.

public interface IFooService
{

}

[Export(typeof(IFooService))]
[PartCreationPolicy(CreationPolicy.Shared)]
class FooSevice : IFooService
{

}

Then the three possible implementation of the View-Model are:

public class TreeItemVM_MefInjection
{
    [Import]
    public IFooService FooService { get; set; }

    public TreeItemVM_MefInjection()
    {
        var catalog = new AssemblyCatalog
          (System.Reflection.Assembly.GetExecutingAssembly());

        var container = new CompositionContainer(catalog);
        container.ComposeParts(this);
    }
}

public class TreeItemVM_ServiceLocator
{
    [Import]
    public IFooService FooService { get; set; }

    public TreeItemVM_ServiceLocator()
    {
        FooService = ServiceLocator.Current.GetInstance<IFooService>();
    }
}

public class TreeItemVM_ManualInjection
{
    public IFooService FooService { get; set; }

    public TreeItemVM_ManualInjection(IFooService fooService)
    {
        FooService = fooService;
    }
}

Each of the tree-view items actually has an ObservableCollection as the tree is hierarchical. Each ViewModel can create it's own children, based on the model data it uses (this is not shown in the above examples just to keep them simple).

So my issues with each of these are:

  1. It seems a lot of code to write to get automatic injection and I'm worried about the performance of creating a catalog and container temporarily. Is this OK to do it like this?
  2. The service locator seems easier but I've read that the service locator is an anti-pattern. Should I be concerned with this?
  3. The last one will give better performance as each instance just passes the IFooService interface on the constructor, and can pass it down to it's children when they are instantiated. However if I want to add more dependency injection latter on I need to change the constructor so maybe automatic injection or service locator maybe better.

So what would people say is the best method? Is there is a defined best practices method to follow? Are all the methods valid is it is up to the company coding standards to define the pattern to use?

Obviously the TreeItems are just normally instanced with new. I don't want these to be exported to MEF as that is overkill and nothing outside of the class library needs to know about them. They are just normal class that need to have MEF dependency injection or find MEF registered interfaces.

Anyone have an opinion on the most desirable solution and any gotchas I should be aware of? I'm sure there are other possible solutions to this as well. Any info would be appreciated.

\$\endgroup\$
5
\$\begingroup\$
  1. Service locator is an anti-pattern because it tends to create implicit dependencies which are not easy to see and usually cause grieve when trying to write unit tests. Especially your implementation which references what seems like a singleton instance which can cause additional problems (i.e. you need to take care to reset it between tests).

    Avoid it.

  2. I can't say much about the MEF injection but it seems roundabout having to write all that code. It also creates an implicit dependency which will probably cause grieve when unit testing your class and makes it directly dependent on MEF while there is no need for it.

    Avoid it.

  3. Clean and simple. Explicit dependency, easy to unit test and injection can be easily manged by any IoC container of your choice (Unity, Ninject, Windsor, etc.).

    The way to go.

\$\endgroup\$
  • 3
    \$\begingroup\$ +1 nice answer. I'll only add that the MEF ViewModel is newing up stuff, which means tight coupling with stuff that's not declared in the constructor; the SL ViewModel is using ambient context and that's bad, the VM could instantiate just about anything; the poor man's DI ViewModel not only looks much cleaner, it says what it wants and that's in line with the Hollywood Principle: don't call them, they'll call you - nobody except your composition root should know there's an IoC container involved, if there's one involved. SL is the exact opposite of that. \$\endgroup\$ – Mathieu Guindon Nov 13 '13 at 13:38
  • \$\begingroup\$ I was going to say exactly the same. By the way, I don't know nothing about MEF but with Unity everything is very simple and approach 3 is automatically resolved. \$\endgroup\$ – Ignacio Soler Garcia Mar 17 '16 at 15:10

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.