How I use Inversion of Control containers

Quite reg­u­larly I get asked by peo­ple how they should use IoC con­tainer in their appli­ca­tion. I don’t think I can answer this ques­tion once and uni­ver­sally because every appli­ca­tion is dif­fer­ent, every appli­ca­tion has dif­fer­ent needs and every appli­ca­tion has dif­fer­ent oppor­tu­ni­ties for lever­ag­ing an Inver­sion of Con­trol container.

How­ever there are some gen­eral rules and pat­terns that I use and I thought I will blog about this instead.

While I use a con­crete exam­ple of Cas­tle Wind­sor, the dis­cus­sion here is universal.It applies to all containers.

Inver­sion of Con­trol means con­tainer does not exist

Container_does_not_exist

Basic dif­fer­ence between an Inver­sion of Con­trol frame­work and any other kind of frame­work is that the con­trol gets inverted. Your appli­ca­tion does not call to the frame­work. Instead the frame­work is aware of your appli­ca­tion and it goes and does its stuff with your application’s objects.

Since Inver­sion of Con­trol Con­tain­ers are Inver­sion of Con­trol frame­works that par­a­digm applies to them as well. They con­trol objects in your appli­ca­tion. They instan­ti­ate them, man­age their life­cy­cle, invoke meth­ods on them, mod­ify them, con­fig­ure them, dec­o­rate them, do all sorts of stuff with them. The main point here is – the appli­ca­tion is com­pletely unaware of that. I feel tempted to put another Matrix anal­ogy here, but hope­fully you get the point with­out it.

The most vis­i­ble man­i­fes­ta­tion of this fact, which clearly illus­trates the lack of any knowl­edge about the con­tainer is that I tend not to ref­er­ence the con­tainer in the appli­ca­tion at all. The only place where the ref­er­ence to the con­tainer does appear is the root project which only runs the appli­ca­tion. It how­ever con­tains no appli­ca­tion logic and serves merely as appli­ca­tion entry point and con­tainer bootstrapper.

Not ref­er­enc­ing the con­tainer at all serves a few pur­poses. Most impor­tantly it helps to enforce good OOP design, and blocks the temp­ta­tion to take short­cuts and use the con­tainer as Ser­vice Loca­tor.

Three calls pat­tern of usage

Now, prob­a­bly the most inter­est­ing part is this sim­ple boot­strap­per. How do I inter­act with the container?

I tend to use pat­tern of three calls to the con­tainer. Yes you heard it right – I only call the con­tainer is three places in the entire appli­ca­tion* (con­di­tions apply, but I’ll dis­cuss this below in just a moment).

My entire inter­ac­tion with the con­tainer usu­ally looks like this:

var container = BootstrapContainer();

finder = container.Resolve<IDuplicateFinder>();
var processor = container.Resolve<IArgumentsParser>();
Execute( args, processor, finder );

container.Dispose();

The three steps are:

  1. Boot­strap the container
  2. Resolve root components
  3. Dis­pose the container

Let’s go over them in turn:

One Install to rule them all…

Boot­strap­ping is incred­i­bly simple:

private IWindsorContainer BootstrapContainer()
{
    return new WindsorContainer()
                  .Install( FromAssembly.This() );
}

The most impor­tant rule here (which is impor­tant in Wind­sor, but good to fol­low with other con­tain­ers that enable this)  is – to call Install just once and reg­is­ter and con­fig­ure all the com­po­nents dur­ing this sin­gle call. Also impor­tant stuff is to use the Install method and Installers to encap­su­late and par­ti­tion reg­is­tra­tion and con­fig­u­ra­tion logic. Most other con­tain­ers have that capa­bil­ity as well. Aut­o­fac and Nin­ject call it mod­ules, Struc­tureMap calls it registries.

As you can see on the screen­shot above I usu­ally have a ded­i­cated folder called Installers in my boot­strap assem­bly where I keep all my installers. I tend to par­ti­tion the installers so that each one of them installs some cohe­sive and small set of ser­vices. So I might have View­Mod­elsIn­staller, Con­trollers Installer, Back­ground­Ser­vicesIn­staller, Log­gin­gIn­staller etc. Each installer is sim­ple and most of them look sim­i­lar to this:

public class ArgumentInterpretersInstaller : IWindsorInstaller
{
    public void Install(IWindsorContainer container, IConfigurationStore store)
    {
        container.Kernel.Resolver.AddSubResolver(new ArrayResolver(container.Kernel));
        container.Register(
            Component.For<IArgumentsParser>()
                .ImplementedBy<ArgumentsParser>().LifeStyle.Transient,
            Component.For<IParseHelper>().ImplementedBy<ParseHelper>(),
            AllTypes.FromAssemblyContaining<IArgumentInterpreter>()
                 .BasedOn<IArgumentInterpreter>()
                 .WithService.Base());
    }
}

This par­ti­tion­ing helps keep things tidy, and by lever­ag­ing Installers you end up writ­ing less code, as now Wind­sor will autodis­cover them and reg­is­ter in just a sin­gle call to FromAssembly.This(). Also another note­wor­thy fact about this, is that you lever­age Inver­sion of Con­trol prin­ci­ple to con­fig­ure the con­tainer itself. Instead of pass­ing the con­tainer around, which should always raise a read flag, you’re telling Wind­sor – con­fig­ure your­self. Nice and tidy.

Another impor­tant thing to notice, is that I tend to lever­age con­ven­tion based reg­is­tra­tion, rather than reg­is­ter­ing all the com­po­nents one by one. This greatly cuts down the size of your reg­is­tra­tion code. It takes the bur­den of reg­is­ter­ing each newly added com­po­nents man­u­ally off of your shoul­ders. It also enforces con­sis­tency in your code, because if you’re not con­sis­tent your com­po­nents won’t get registered.

* yes – I do inter­act with the con­tainer in the installers, so I clearly break the three calls rule, right? No – I inter­act with the con­tainer in objects that extend, or mod­ify the con­tainer itself – in this case it’s obvi­ously not a bad thing.

…and in one Resolve bind them

Sim­i­lar to unit tests prin­ci­ple – one log­i­cal assert per tests, I fol­low the rule of allow­ing explicit call to resolve in just one place in the entire appli­ca­tion. Usu­ally this will be just one call, that pulls the root com­po­nent (Con­troller in MVC appli­ca­tion, Shell in WPF appli­ca­tion, or what­ever the root object in your app is). In the exam­ple above I have two root objects so I have two calls to Resolve. That’s usu­ally OK. How­ever if you have more than three, you might want to take a closer look at rea­sons for that, as it’s quite unlikely you really need this.

The impor­tant thing is to have the Resolve calls in just this one sin­gle place and nowhere else in your appli­ca­tion. Why that’s impor­tant? To fully lever­age container’s poten­tial, instead of telling it at every step what it should do. Let it spread its wings.

Clean up

It is impor­tant to let the con­tainer clean up after itself, when its done doing its job. In this case I can not only say that this is some­thing I do. You also always should dis­pose your con­tainer at the end of your appli­ca­tion. Always, no excep­tions. This will let the con­tainer to shut­down grace­fully, decom­mis­sion all the com­po­nents, give them chance to clean up after them­selves, and free all the resources they may occupy.

 

What about you? How do you use your container?

  • Omer Mor

    Thanks for shar­ing.
    Your usage looks much like how I was using my con­tainer, when I only used it to cre­ate sin­gle­tons.
    How­ever since I started to cre­ate tran­sient objects as well I found myself resolv­ing in more places.
    Can you address the issue of tran­sients please?

  • http://kozmic.pl/Default.aspx Krzysztof Koźmic

    @Omer — I will, that's the next post. I actu­ally did show this already in pre­vi­ous posts, I just didn't call that "how I resolve tran­sient com­po­nents from the container."

  • http://kozmic.pl/Default.aspx Krzysztof Koźmic

    @Omer — I will, that's the next post.

  • John Simons

    Awe­some post, thanks mate.
    Look­ing for­ward to the next post about deal­ing with tran­sients :)

  • http://davesquared.net/ David Tchepak

    Thanks for the really inter­est­ing post.

    I am keen to see how you han­dle wiring up views to [presenters|controllers|view mod­els]. I've com­monly resorted to expos­ing a restricted inter­face of the con­tainer (View­Fac­tory) so I can use the con­tainer to resolve views, but this has always felt dirty to me (and breaks your rule of only one call to Resolve). Any suggestions?

  • Phil Hoy

    How do you deal with reusing installers across solutions?

  • http://kozmic.pl/Default.aspx Krzysztof Koźmic

    @Phil,

    Installers are pretty focused. Why would I want to reuse them?
    Can you explain what you mean?

  • Eli Thomp­son

    Would it also be the case in a Web­Forms web­site that I'd need to resolve the root com­po­nents on the ASPX pages because each of those pages is an entry point of the application?

  • http://nblumhardt.com/ Nicholas Blumhardt

    I think this is good gen­eral advice, you should be clearer though that assem­bly ref­er­ences aren't a prob­lem per se, but more of a rule of thumb when using cer­tain containers.

    For exam­ple, many IoC libraries (Nin­ject, MEF, Unity) use attrib­utes for con­fig­u­ra­tion. These require assem­bly ref­er­ences, but regard­less of your feel­ings about attrib­utes, they don't make the result any less "best prac­tice" IoC.

    Nit-picking, I know. Enjoyed the arti­cle! :)

  • http://blog.ploeh.dk/ Mark See­mann

    @Nicholas Blumhardt: I have to take sides with Krzysztof here. If you have an assem­bly ref­er­ence because you need to apply attrib­utes, you make it much eas­ier to make fur­ther mis­takes. Expe­ri­enced devel­op­ers like you are not likely to fall vic­tim to that, but (DI) beginnners might.

    It also becomes much harder (per­haps even impos­si­ble) to write unit tests that safe­guards against incor­rect cou­pling (con­sider this exam­ple: blogs.msdn.com/…/…shouldnotreferenceunity.aspx).

  • Phil Hoy

    You might want to share an installer if a com­po­nent is used in a cou­ple of apps. say a win­dows app and a web app.

  • http://kozmic.pl/Default.aspx Krzysztof Koźmic

    @Phil

    Than it's not an issue. You're free to reuse the installers any­way you like. They dont have to be tied to any par­tic­u­lar host in anyway

  • Phil Hoy

    Sorry I was not clear.

    Where would you put the installer classes for a com­po­nent from an assem­bly when the assem­bly is used in two dif­fer­ent solutions.

    Would you copy the installer class and put in in the top level projects in each solu­tions or would you put it in with the assem­bly with the installed components?

  • http://kozmic.pl/Default.aspx Krzysztof Koźmic

    Yeah, I usu­ally copy the code. It's not worth reusing this on binary level, since you're likely to do small tweaks, spe­cific to the project at hand.

  • Morten Jacob­sen

    Hi,

    Could you com­ment on how you would wire up views and pre­sen­ters (Win­Forms MVP) with this approach?

    Regards,
    Morten

  • http://kozmic.pl/Default.aspx Krzysztof Koźmic

    @Morten Jacob­sen

    Just like any other com­po­nent? I can't see any­thing spe­cial about them. Can you elab­o­rate what exactly are you hav­ing doubts about?

  • Morten Jacob­sen

    @Krzystof

    Maybe I'm wrong, I was just think­ing that the cir­cu­lar nature would screw some­thing up (i.e. the view has to know the pre­sen­ter, and the pre­sen­ter has to know the view)? Nat­u­rally, both con­struc­tors can't accept the depen­dency (i.e. SomeView(SomePresenter pre­sen­ter) and SomePresenter(SomeView view)), so how do you over­come this? Do you have a prop­erty that wind­sor will inject e.g. the pre­sen­ter into or do you use another technique..

    This may seem like a stu­pid ques­tion, but I'm still new to Wind­sor, so I'm still in the learn­ing process..

  • http://kozmic.pl/Default.aspx Krzysztof Koźmic

    @Morten Jacob­sen

    in class­ing MVP view has no knowl­edge of the presenter.

    Speak­ing more broadly, Wind­sor will not do any magic. You need to break depen­dency cycles your­self, usu­ally one object sets itself to a prop­erty of another in this kinds of situations.