What's new in Windsor 3: Service Locator usage detection

As we're near­ing the release date of Cas­tle Wind­sor 3.0 (code­name Wawel) I will be blog­ging about some of the new fea­tures and improve­ments intro­duced in the new version.

One of the fea­tures that were intro­duced in cur­rent ver­sion 2.5 was sup­port for debug­ger diag­nos­tic views in Windsor.

In Wawel one of the improve­ments is addi­tion of a new diag­nos­tic — detec­tion of cases where the con­tainer is being used as Ser­vice Loca­tor. For those unfa­mil­iar with what Ser­vice Loca­tor is, it's an approach that breaks the basic rule of Inver­sion of Con­trol, by explic­itly call­ing out to the con­tainer from within application.

Here's where I tell you Ser­vice Loca­tor is bad

I spent last two days read­ing through the Stack­Over­flow archive of IoC related ques­tions and one of the most com­mon sources of prob­lems is that con­tainer is being used as Ser­vice Locator.

I wrote why Ser­vice Loca­tor (par­tic­u­larly when imple­mented via IoC con­tainer) is a bad idea on few occa­sions (for exam­ple here). Also Mark has a good overview of draw­backs of this approach so I won't rehash it again.

Good news is — even if some­one from your team starts using the con­tainer as Ser­vice Loca­tor, Wind­sor will now help you detect those cases.

Here's where I give you an example

Take a look at the fol­low­ing class:

[Singleton]
public class ComponentFactory
{
    private readonly IKernel kernel;

    public ComponentFactory(IKernel kernel)
    {
        this.kernel = kernel;
    }

    public object Create(String name)
    {
        return kernel.Resolve<object>(name);
    }
}

It is part of the appli­ca­tion layer (and not infra­struc­ture layer) and as such it should not be aware of the con­tainer, yet it depends on IKer­nel. Also quick look at its Cre­ate method is enough to see that it most likely is passed around through­out the appli­ca­tion and used to pull com­po­nents from the con­tainer with­out giv­ing it much thought, which as you're surely guess­ing by now is a recipe for trouble.

Here's where I show you how it looks

If you nav­i­gate in debug mode to a con­tainer instance where com­po­nents like the one described above exists a new entry in the debug­ger view will appear list­ing those components.

sl-detection

Here's where I tell you how it works

Wind­sor doesn't have the whole pic­ture of your appli­ca­tion, so it can only detect a sub­set of cases of Ser­vice Loca­tor usage. In par­tic­u­lar it is unable to detect the case when a Ser­vice Loca­tor is built com­pletely on top of the con­tainer as com­monly found, where con­tainer is assigned to a pub­lic field of a sta­tic class and accessed through that field.

Since Wind­sor only knows about the com­po­nents you reg­is­ter with it, it looks for com­po­nents that depend on the con­tainer and are not extend­ing infra­struc­ture of the con­tainer itself (like for exam­ple Inter­cep­tors are). All such com­po­nents are flagged as poten­tial ser­vice loca­tor and pre­sented to you.

I hope you'll find this fea­ture useful.

Here's where you tell me what you think

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

    Great idea. I think the default behav­ior should be that the con­tainer should throw an excep­tion when­ever it detects one of these scenarios.

    You could take it fur­ther: to prop­erly detect when the con­tainer is wrapped in a Sin­gle­ton it should throw an excep­tion (con­fig­urable) upon the sec­ond call to Resolve on the same thread/context.

    • http://twitter.com/kkozmic Krzysztof Kozmic

      @mark

      that would be dras­tic :)

      • https://www.google.com/accounts/o8/id?id=AItOawkAE8Kx9Qau-Q6TTuzbRE6h65sl4TaeHMQ Damian Pow­ell

        I think Mark's sug­ges­tion makes sense, actu­ally. It's the first thing that occurred to me when I read your post. I think that it should throw one of those use­ful excep­tions that point peo­ple in the direc­tion of Typed or Del­e­gate Ser­vice Fac­to­ries, or Dis­trib­uted Com­pos­ite Roots, or one of the other solu­tions to the Ser­vice Loca­tor anti-pattern. It should be pos­si­ble to dis­able that behav­iour though for the cases where the con­tainer is being intro­duced into a legacy appli­ca­tion. We're at the dawn of a major ver­sion hike — now is def­i­nitely the time to do this as it would be an unac­cept­able thing to intro­duce in a point release.

  • http://twitter.com/xelibrion Dmitry Kryuchkov

    How Wind­sor will treat typed fac­tory in this case?

    • http://twitter.com/kkozmic Krzysztof Kozmic

      @Dmitry Kryuchkov

      That's a good ques­tion. Typed fac­to­ries surely can be used as ser­vice loca­tor
      pub­lic inter­face IGe­tAny­thing
      {
      T GiveMe();
      }

      How­ever due to flex­i­bil­ity of typed fac­to­ries it's hard to say with any con­fi­dence if the fac­tory can or can­not be used in that man­ner.
      At the end of the day it's about help­ing peo­ple locat­ing issues in their code and I sup­pose if I have to draw a line, it would be assum­ing users con­scious enough to use a typed fac­tory in the first place will be more aware, and avoid, those prob­lems themselves.

      • http://twitter.com/xelibrion Dmitry Kryuchkov

        So Wind­sor will not detect typed fac­to­ries as poten­tial ser­vice loca­tor usages?

        • Krzysztof

          @Dmitry
          No, it gives typed fac­to­ries the ben­e­fit of a doubt.

        • http://twitter.com/kkzmc Krzysztof Koźmic

          @Dmitry
          No, it gives typed fac­to­ries the ben­e­fit of a doubt.

  • Pingback: Krzysztof Koźmic's blog » What’s new in Windsor 3: Container debugger diagnostics improvements

  • Pingback: What's new in Windsor 3: Container debugger diagnostics improvements - Krzysztof Kozmic - Devlicio.us - Just the Tasty Bits