Best Practices for IOC Container
Asked Answered
U

6

27

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.

Ultrasonics answered 26/1, 2009 at 16:2 Comment(0)
U
15

Put the IOC container at the highest level / entry point in the process and use it to inject dependencies in everything underneath it.

Ultrasonics answered 1/9, 2009 at 22:2 Comment(0)
T
23

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.

Tenace answered 8/10, 2009 at 11:55 Comment(3)
And so says the book. Lets say Foo has a method => Foo.SendEamil<T>(T value). And you need to instantiate an instance of IEmail<T> to match it. In such case, you can create a convoluted factory class, or just inject in the container itself.Progeny
Great advice. I think you don't even have to create a new factory class, just use "Func<ISomething> sthFactory" as an injected parameter and Unity will handle it. Later you can just call var sth = sthFactory();Apis
@JarekKardas You are correct, the new version of Unity supports this. The version that was current when I answered the question did not have that feature ;).Tenace
U
15

Put the IOC container at the highest level / entry point in the process and use it to inject dependencies in everything underneath it.

Ultrasonics answered 1/9, 2009 at 22:2 Comment(0)
S
6

you can register the container in itself and have it injected like every other dependency property, like so:

IUnityContainer container = new UnityContainer();
container.RegisterInstance<IUnityContainer>(container);

classes that need to access it will have the following property:

private IUnityContainer unityContainer;
[Dependency]
public IUnityContainer UnityContainer
{
    get { return unityContainer; }
    set { unityContainer = value; }
}

thus, the container is injected whenever an instance of such a class is resolved/built up.

This is more flexible as it works for multiple containers within the same application, which would not be possible with the singleton pattern.

Sinistral answered 26/1, 2009 at 16:25 Comment(2)
Unity container registers itself with IUnityContainer automatically, young grass hopper.Progeny
IOC container resolving itself... who woulda thunk it.Digitiform
T
2

If all of your objects need a reference to the container then you should look into reworking the code some. While still preferable to calling new everywhere it still scatters the responsibility of building your object graphs throughout your code. With that kind of usage it strikes me as being used more like a ServiceLocator instead of a IoC Container.

Tobacco answered 26/1, 2009 at 17:19 Comment(2)
The application I'm working on uses Com+ for all data access. I've been using the IOC container to instantiate these objects so I can put in a test double if need beUltrasonics
So the way I'm doing things I'd have to have all data access limited to one class with also has the IOC container which is hard to do.Ultrasonics
Q
0

Another option would be using the CommonServiceLocator, although it may be a pointless indirection, you may use the ServiceLocator.Current as the instance known by all classes

Quintillion answered 20/4, 2009 at 16:13 Comment(0)
A
0

I have a post on this subject at my blog where I´m using something along the lines of t3mujin answer. Feel free to use it (don´t bother that it´s sharepoint related...that doesn´t matter):

http://johanleino.spaces.live.com/blog/cns!6BE273C70C45B5D1!213.entry

Avow answered 23/5, 2009 at 16:10 Comment(1)
Sigh.. Having fun reinventing the wheel much? A square one too that is. Have a look at this commonservicelocator.codeplex.com.Progeny

© 2022 - 2024 — McMap. All rights reserved.