views:

515

answers:

5

Hi,

we want to use Unity for IOC. All i've seen is the implementation that there is one global static service (let's call it the the IOCService) which holds a reference to the Unity container, which registers all interface/class combinations and every class asks that object: give me an implementation for Ithis or IThat.

Frequently i see a response that this pattern is not good because it leads to a dependency from ALL classes to the IOCService (not to the Unity container because it is only known inside the IOCService).

But what i don't see often, is: what is the alternative way?

Michel

EDIT: found out that the global static service is called the service locator, added that to the title.

+5  A: 

Instead of using the container explicitly, use it implicitly by leveraging constructor / property injection instead. Create a core class (or set of core classes) that depend on all the major pieces of your application.

Most containers will let you put ISomething[] in your constructor and it will inject all instances of ISomething into your class.

This way, when you bootstrap your application:

  1. Instantiate your container
  2. Register all your goodies
  3. Resolve the core classes (this will pull in all the other dependencies you need)
  4. Run the "main" part of the application

Now, depending on the type of application you are writing, there are different strategies for avoiding marking the IoC container as "static".

For ASP.NET web applications, you'll probably end up storing the container in the Application State. For ASP.NET MVC applications, you need to change out the Controller Factory.

For desktop applications, things get more complicated. Caliburn uses an interesting solution to this problem using the IResult construct (this is for WPF applications but could be adapted for Windows Forms as well.

Garo Yeriazarian
Unity will not resolve `ISomething[]` or `IEnumerable<ISomething>` in a constructor resolution. You have to use `InjectionConstructor` if you need to pass a list of registered dependencies. This kind of sucks as that means that those dependencies are resolved once at the startup, thus not allowing transient lifetime. Would be happy to know if there is a better solution.
Igor Zevaka
If you need the new instances to be injected into your code at runtime, then you should have an explicit way for that to happen (not injected by the IoC container). You can set up an event aggregator to notify when a new instance of a particular type arrives.
Garo Yeriazarian
@Igor - you can also solve that by injecting a factory that can create new transient instances at runtime.
Jeff Sternal
+6  A: 

The alternative is to have a single instance of your container at the highest application level only, then use that container to resolve every object instance you need to create in that layer.

For example, the main method of most executables just looks like this (minus exception handling):

private static void main(string[] args) {

     Container container = new Container();

     // Configure the container - by hand or via file

     IProgramLogic logic = container.Resolve<IProgramLogic>();

     logic.Run();
}

Your program (represented here by the IProgramLogic instance) doesn't have to know anything about your container, because container.Resolve will create all its dependencies - and its dependencies' dependencies, on down to leaf classes with no dependencies of their own.


ASP.NET is a harder case, because web forms doesn't support constructor injection. I typically use Model-View-Presenter in my web forms applications, so my Page classes really only have one dependency each - on their presenter. I don't unit test them (everything interesting and testable is in my presenters, which I do test), and I don't ever substitute presenters. So I don't fight the framework - I just expose a container property on my HttpApplication class (in global.asax.cs) and use it directly from my Page files:

protected void Page_Load(object sender, EventArgs args) {
    ICustomerPresenter presenter = Global.Container.Resolve<ICustomerPresenter>();
    presenter.Load();
}

That's service locator of course - though the Page classes are the only thing coupled to the locator: your presenter and all of its dependencies are still fully decoupled from your IoC container implementation.

If you have a lot of dependencies in your Page files (that is, if you do not use Model-View-Presenter), or if it's important to you to decouple your Page classes from your Global application class, you should try to find a framework that integrates into the web forms request pipeline and use property injection (as suggested by Nicholas in the comments below) - or write your own IHttpModule and perform the property injection yourself.

Jeff Sternal
I implement this this in a very similar way. In my case, Global is IoCContainer and Container is GetInstance. This is the only class in the entire app in which singleton is written by hand (all the other classes are singleton or not dependending on Unity configuration). This class (Global/IoCContainer) is in a project named Configuration. This project is only referenced by UI, and it references all the projects (except UI) to be able to instantiate the proper objects.
bloparod
This is still the same pattern (Service Locator) that is frequently advised against. Even in ASP.NET WebForms it is possible to achieve Dependency Injection either via property injection (http://code.google.com/p/autofac/wiki/AspNetIntegration#Implementing_WebForms_Pages_and_User_Controls) or by refactoring to a presenter-driven approach.
Nicholas Blumhardt
I agree with Nicholas; besides that this answer sounds logical, it is still a service locator?
Michel
@Michael - it is indeed using service locator, though within narrow boundaries that I think are defensible (because of the constraints asp.net web forms imposes on us). I don't know what possessed me to use asp.net for my example, since it doesn't facilitate proper dependency injection techniques. I'll try to update my answer later today to explain better.
Jeff Sternal
+2  A: 

If your concern is having a dependency on Unity throughout your application, you can combine the service locator with a facade to hide the IOC implementation. In this way, you do not create a dependency on Unity in your application, only on having something that can resolve types for you.

For example:

public interface IContainer
{
    void Register<TAbstraction,TImplementation>();
    void RegisterThis<T>(T instance);
    T Get<T>();
}

public static class Container
{
    static readonly IContainer container;

    public static InitializeWith(IContainer containerImplementation)
    {
        container = containerImplementation;
    }

    public static void Register<TAbstraction, TImplementation>()
    {
        container.Register<TAbstraction, TImplementation>();
    }

    public static void RegisterThis<T>(T instance)
    {
        container.RegisterThis<T>(instance);
    }

    public static T Get<T>()
    {
        return container.Get<T>();
    }
}

Now all you need is an IContainer implementation for your IOC container of choice.

public class UnityContainerImplementation : IContainer
{
    IUnityContainer container;

    public UnityContainerImplementation(IUnityContainer container)
    {
        this.container = container;
    }

    public void Register<TAbstraction, TImplementation>()
    {
        container.Register<TAbstraction, TImplementation>();
    }

    public void RegisterThis<T>(T instance)
    {
        container.RegisterInstance<T>(instance);
    }

    public T Get<T>()
    {
        return container.Resolve<T>();
    }
}

Now you have a service locator that is a facade for IOC services, and can configure your service locator to use Unity or any other IOC container. The rest of the application has no dependency on the IOC implementation.

To configure your service locator:

IUnityContainer unityContainer = new UnityContainer();
UnityContainerImplementation containerImpl = new UnityContainerImplementation(unityContainer);
Container.InitializeWith(containerImpl);

For testing, you can create a stub of IContainer that returns whatever you want, and initialize Container with that.

Jay
Service locator *is* the problem (at least for many people), not just a concrete dependency on a particular dependency injection container. Mark Seemann [has written very clearly about the problems with service locator here](http://blog.ploeh.dk/2010/02/03/ServiceLocatorIsAnAntiPattern.aspx).
Jeff Sternal
Nice code indeed, but a lot of people have issues against the service locator pattern (because it creates a dependency to the service locator class, not just to the Unity classes) but the problem is that i've never seen a good alternative, that's why i asked.
Michel
@Jeff: very nice article in your link
Michel
+3  A: 

In theory, to not have to worry about having a static IoC instance, you need to follow the Fight Club Rule - i.e. not to talk about the fight club - i.e. not to mention the IoC container.

This means that your components should largely be unaware about the IoC container. It should only be used at the topmost level when registering components. If a class needs to resolve something, it should really be injected as a dependency.

The trivial case is easy enough. If PaymentService depends on IAccount, the latter should be injected by IoC:

interface IAccount {
  Deposit(int amount);
}

interface CreditCardAccount : IAccount {
  void Deposit(int amount) {/*implementation*/}
  int CheckBalance() {/*implementation*/}
}

class PaymentService {

  IAccount account;

  public PaymentService (IAccount account) {
    this.account = account;
  }

  public void ProcessPayment() {
    account.Deposit(5);
  }
}
//Registration looks something like this
container.RegisterType<IAccount, CreditCardAccount>();
container.RegisterType<PaymentService>();

The not so trivial case is where you want to inject multiple registrations. This especialy applies when you are doing any sort of Converntion Over Configuration and creating an object from a name.

For our payment example, say you want to enumerate through all accounts and check their balances:

class PaymentService {

  IEnumerable<IAccount> accounts;

  public PaymentService (IEnumerable<IAccount> accounts) {
    this.accounts = accounts;
  }

  public void ProcessPayment() {
    foreach(var account in accounts) {
      account.Chackbalance();
    }
  }
}

Unity has the ability to register multiple interface to class mappings (they have to have different names thought). It does not, however, automatically inject those into classes that take collections of those registered interfaces. So, the above example will throw a resolution failed exception at runtime.

If you don't care that those objects live forever, you can register PaymentService in a more static fashion:

container.RegisterType<PaymentService>(new InjectionConstructor(container.ResolveAll<IAccount>()));

The above code will register PaymentService and will use a collection of IAccount instances that is resolved at registration time.

Alternatively, you can pass an instance of the container itself as a dependency and let PaymentService perform resolution of accounts. This is not quite following the Fight Club Rule, but is slightly less smelly than static Service Locator.

class PaymentService {

  IEnumerable<IAccount> accounts;

  public PaymentService (IUnityContainer container) {
    this.accounts = container.ResolveAll<IAccount>();
  }

  public void ProcessPayment() {
    foreach(var account in accounts) {
      account.Chackbalance();
    }
  }
}
//Registration is pretty clean in this case
container.RegisterType<IAccount, CreditCardAccount>();
container.RegisterType<PaymentService>();
container.RegisterInstance<IUnityContainer>(container);
Igor Zevaka
+6  A: 

+1 for knowing that Service Locator is a Bad Thing.

Problem is - Unity is not very sophisticated so I don't know how easy/hard is it to do IoC the right way with it.

I wrote few blogposts recently that you might find useful.

Krzysztof Koźmic
+1 Those articles sums it up pretty well. Unity understands Constructor Injection, so the first post translates directly. AFAIK, Unity doesn't support dynamically emitted Factories, but the usage pattern regarding Abstract Factory still applies - you would just have to manually implement the concrete Factories, but it's pretty trivial to do so.
Mark Seemann
Unity 2.0 supports delegate based automatic factories.
Chris Tavares