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

As we’re nearing the release date of Castle Windsor 3.0 (codename Wawel) I will be blogging about some of the new features and improvements introduced in the new version.

One of the features that were introduced in current version 2.5 was support for debugger diagnostic views in Windsor.

In Wawel one of the improvements is addition of a new diagnostic – detection of cases where the container is being used as Service Locator. For those unfamiliar with what Service Locator is, it’s an approach that breaks the basic rule of Inversion of Control, by explicitly calling out to the container from within application.

Here’s where I tell you Service Locator is bad

I spent last two days reading through the StackOverflow archive of IoC related questions and one of the most common sources of problems is that container is being used as Service Locator.

I wrote why Service Locator (particularly when implemented via IoC container) is a bad idea on few occasions (for example here). Also Mark has a good overview of drawbacks of this approach so I won’t rehash it again.

Good news is – even if someone from your team starts using the container as Service Locator, Windsor will now help you detect those cases.

Here’s where I give you an example

Take a look at the following 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 application layer (and not infrastructure layer) and as such it should not be aware of the container, yet it depends on IKernel. Also quick look at its Create method is enough to see that it most likely is passed around throughout the application and used to pull components from the container without giving it much thought, which as you’re surely guessing by now is a recipe for trouble.

Here’s where I show you how it looks

If you navigate in debug mode to a container instance where components like the one described above exists a new entry in the debugger view will appear listing those components.

sl-detection

Here’s where I tell you how it works

Windsor doesn’t have the whole picture of your application, so it can only detect a subset of cases of Service Locator usage. In particular it is unable to detect the case when a Service Locator is built completely on top of the container as commonly found, where container is assigned to a public field of a static class and accessed through that field.

Since Windsor only knows about the components you register with it, it looks for components that depend on the container and are not extending infrastructure of the container itself (like for example Interceptors are). All such components are flagged as potential service locator and presented to you.

I hope you’ll find this feature useful.

Here’s where you tell me what you think

Comments

Mark Seemann says:

Great idea. I think the default behavior should be that the container should throw an exception whenever it detects one of these scenarios.

You could take it further: to properly detect when the container is wrapped in a Singleton it should throw an exception (configurable) upon the second call to Resolve on the same thread/context.

@mark

that would be drastic 🙂

I think Mark’s suggestion makes sense, actually. It’s the first thing that occurred to me when I read your post. I think that it should throw one of those useful exceptions that point people in the direction of Typed or Delegate Service Factories, or Distributed Composite Roots, or one of the other solutions to the Service Locator anti-pattern. It should be possible to disable that behaviour though for the cases where the container is being introduced into a legacy application. We’re at the dawn of a major version hike – now is definitely the time to do this as it would be an unacceptable thing to introduce in a point release.

How Windsor will treat typed factory in this case?

@Dmitry Kryuchkov

That’s a good question. Typed factories surely can be used as service locator
public interface IGetAnything
{
T GiveMe();
}

However due to flexibility of typed factories it’s hard to say with any confidence if the factory can or cannot be used in that manner.
At the end of the day it’s about helping people locating issues in their code and I suppose if I have to draw a line, it would be assuming users conscious enough to use a typed factory in the first place will be more aware, and avoid, those problems themselves.

So Windsor will not detect typed factories as potential service locator usages?

Krzysztof says:

@Dmitry
No, it gives typed factories the benefit of a doubt.

@Dmitry
No, it gives typed factories the benefit of a doubt.

[…] Proxy Tutorial « What’s new in Windsor 3: Service Locator usage detection […]