Best Practices for IOC Container

Ryu picture Ryu · Jan 26, 2009 · Viewed 8.9k times · Source

I'm using the Unity IOC container and I'm just wondering what is the best best way to access the container for multiple classes.

Should every class have an IUnityContainer member and then pass the container in by constructor? Should there be a singleton class with an IOC container?

How about asp.net development?

Could somebody guide me in the right direction? Thanks.

Answer

Thorsten Lorenz picture Thorsten Lorenz · Oct 8, 2009

IMHO it is not advisable to inject the entire container into a class or to have an application wide static IoC service locator.

You want to be able to see from the constructor of a class (lets call it Foo), what kind of services/objects it is using to get the work done. This improves clarity, testability and degubability.

Lets say Foo only needs the email service, but I pass in the whole container and somewhere in the code the email service gets resolved from the container. In this case it will be very hard to follow. Instead it is better to inject the email service directly to state Foo's dependencies clearer.

If Foo needs to create multiple instances of the email service, it is better to create and inject an EmailServiceFactory (via the IoC container), which will create the required instances on the fly.

In the latter case, Foo's dependencies are still indicated as specific as possible - only the ones, that the EmailServiceFactory can create. Had I injected the whole container, it would not be clear what services provided by it are Foo's exact dependencies.

Now, if I later want to provide different instances of the email service, I swap it out inside the EmailServiceFactory. I could swap out the whole factory as well, if all the services it creates need to be swapped (e.g. during testing).

So at the cost of creating one extra class (the factory), I get much cleaner code and won't have to worry about curious bugs that may occur when global statics are used. Additionally when supplying mocks for testing, I know exactly what mocks it needs and don't have to mock out an entire container's types.

This approach also has the advantage, that now, when a module is initialized (only applies to Prism / Modularity), it doesn't have to register all of the types of objects it supplies with the IoC container. Instead it can just register its ServiceFactory which then supplies those objects.

To be clear, the module's initialization class (implements IModule) should still receive the application wide IoC container in its constructor in order to supply services, that are consumed by other modules, but the container should not invade into the module's classes.

Finally, what we have here is another fine example of how an extra layer of indirection solves a problem.