Service locator is not an anti pattern.

(this article have been rewritten since it didn’t seem like I managed to communicate my thoughts properly)

There are several blog posts that states that service locator is an anti pattern. With this article I’ll try to explain why it’s not. Do understand that I’m not saying that it should be used for dependency management.

Let’s start by examining where the pattern doesn’t fit (which most blog entries uses as a “proof” for when it’s an anti pattern).

Here are two quotes from different blogs:

In short, the problem with Service Locator is that it hides a class’ dependencies, causing run-time errors instead of compile-time errors, as well as making the code more difficult to maintain because it becomes unclear when you would be introducing a breaking change.

The problem with a Service Locator is that it hides dependencies in your code making them difficult to figure out and potentially leads to errors that only manifest themselves at runtime. If you use a Service Locator your code may compile but hide the fact that the Service Locator has been incorrectly configured. At runtime, when your code makes use of the Service Locator to resolve a dependency that hasn’t been configured, an error will occur. The compiler wasn’t able to help. Moreover, by using a Service Locator you can’t see from the API exactly what dependencies a given class may have.

So what they are saying is that the pattern can hide dependencies and force you to run your application to discover it. I fully agree. It can do that.

Here is the most common example to illustrate that:

public class SomeService
{
	public void DoSomething()
	{
		ServiceLocator.Resolve<ISomeRepository>().Save("kdd");
	}
}

I agree 100%. The service locator do not work very well in that case. I strongly discourage you from abusing the locator in that way. Dependencies/information which is required should always be injected through the constructor. So a better solution would be:

public class SomeService
{
	ISomeRepository _repos;
	
	public SomeService(ISomeRepository repos);
	{
		if (repos == null) throw new ArgumentNullException("repos");
		
		_repos = repos;
	}
	public void DoSomething()
	{
		_repos.Save("kdd");
	}
}

Is it an anti-pattern?

We have identified use cases where the pattern doesn’t fit. Does that make it an anti pattern? Of course not. Let’s examine when it’s perfectly valid.

Let’s start with the very definition of service locator (from wikipedia):

The service locator pattern is a design pattern used in software development to encapsulate the processes involved in obtaining a service with a strong abstraction layer. This pattern uses a central registry known as the “service locator” which on request returns the information necessary to perform a certain task.

What it’s saying is that the service locator basically is something that abstracts away the mapping between the requested type and implementations of something. That is that when requesting a service we do not have to care about the actual implementation.

Doesn’t that sound awfully a lot like a inversion of contol container. It does. Because an IoC container is nothing more than a service locator with lifetime management when all registrations have been configured.

Let’s start by taking an example from the SimpleInjector documentation:

public partial class User : BasePage
{
    private readonly IUserRepository repository;
    private readonly ILogger logger;

    public User()
    {
        // 5. Retrieve instances from the container (resolve)
        this.repository = Global.Container.GetInstance<IUserRepository>();
        this.logger = Global.Container.GetInstance<ILogger>();
    }

    protected void Page_Load(object sender, EventArgs e)
    {
        // Use repository and logger here.
   }
}

He do warn about using the container as service locator. But the point is that every container can be used as a service locator. Why is that? Because it’s the easiest way to allow others to take advantage of all services that the container manages.

So when you are using any framework that have IoC support (like ASP.NET MVC) you can safely assume that they use the service location features of your favorite container.

Summary

My point is that you can abuse any pattern, but that doesn’t make it an anti pattern. The reason to why Singleton and Service Locator got such a bad reputation is that they are easy to understand, implement and use. The problem is that the implementors/users haven’t fully understood the problem that the patterns are trying to solve.

Here is a challenge for all of you that claims that it’s an anti pattern:

Pretend that you are developer at Microsoft working with ASP.NET MVC. You want to let your framework users inject dependencies into the Controllers. But since you’ve read that service location is an anti pattern you’ll want to replace it with something else (which supports scoping).

Anyone of you that can present a solution which is cleaner than my defined interfaces above will get my eternal respect.


  • Gurra777

    Good thougts.

  • Mikael Klint

    Very good article.
    Somewhere you have to kickstart the IoC. As a part of the framework, service location is a good pattern when kickstarting the IoC. Though service location should never be used in a domain code.

  • Robert Slaney

    Nice view point. Contrast MVC 1 with MVC 3 / 4. There were many factories in MVC 1 that you could hook into to introduced DI into the stack, like the ControllerFactory.

    Move forward into MVC 3 and the DependencyResolver now replaces most of the static Factory and Provider wrappers, but you have no idea what will be asked for in the GetService call without running the application. At best you be asked for all instances at bootstrap, at worst it will be in dribs and drabs as the application executes.

    The key is a good DI solution to control the aspect of the framework/API that instantiates your objects. Using a locator does not achieve that aim.

    Let’s revisit the MVC4 dependency resolver.
    There are 3 interfaces/abstract classes it will ask for :
    IViewPageActivator, IControllerFactory and ModelMetadataProvider. But you would never know that without running the application. If you using the WebAPI it will also request IHttpControllerActivator.

    I would much prefer an ObjectFactory approach where each “service” is an virtual property and/or method. This way you could easily get the current implementation and then wrap and provide a facade if required. You cannot do this with MVC4 as the default implementation is only created if you don’t supply an instance from GetService, but by then it’s too late in inject your own. Even worse is that the default implementations are usually internal or private classes.

    With WCF you can accomplish DI by providing an IInstanceProvider implementation.

    • http://www.gauffin.org jgauffin

      That’s probably the best comment I’ve got so far regarding my service locator post (here and at CodeProject.com).

      Yeah. The extension points in ASP.NET MVC is a bit cumbersome. They should have had someone which is responsible of designing all extension points so that they’ve got a unified API.

      I think that they created the DependencyResolver just because most users will use the IoC container to provide everything. But it should really have been split up into two different service locators. One for framework integration and one for injecting business classes.

      The problem with the current solution is that it’s not clear what the lifetime is for each service should be. For instance I’ve tried to use DependencyResolver to register the validator and metadata providers for my Griffin.MvcContrib in MVC. That didn’t work very well since they did not get the lifetime that I expected.

      However, if we look at the DependencyResolver from a strict integration point for your average LOB application it’s great. Since in that case the framework can’t really tell what’s getting injected. You also get scoping around the HTTP request (i.e. the IoC container can clean up everything when the child scope is disposed) and it’s easy to create the adapter. Hence I would probably still use it instead of the IHttpControllerActivator.

      But if we look at the extension points for the framework the DependencyResolver isn’t really that great. The abstract factory that you suggested would probably have been a better solution. You forgot the ModelValidatorProvider though. There can be several implementations of it at the sametime. So the existing singleton should probably be left.

      My WCF integration can be found here: https://github.com/jgauffin/Griffin.Container/blob/master/Source/Griffin.Container.Wcf/ServiceLocatorInstanceProvider.cs (another file contains the

  • ben

    After 10 years of using it I’m beginning to think IOC / DI is an Anti Pattern ….so the fact that a service Locator is also one doesn’t surprise me .

    The fact is an IOC container ( and a service locator ) expose a significant amount of code to anyone that has access to it . Mark Miller wrote a very good paper a number of years ago how classes should be regarded as capabilities and should obey POLA .

    Yes you can use constuctor injection but this just limits its badness and introduces worse issues like rarely used but expensive objects. This means you need to be aware how expensive an object is to create and how much its used to determine whether to use DI … which is not a good thing .. And then what do you do ? Call the Container in the methods that use it ? Lazy load it ( Which may be an issue if it uses a lot of memory and is not disposed) . Obviously the best thing is to pass it in from the caller .. but if that is valid why inject from the constructor ? Is it just because we have a proliferation of infra structure objects / factories which dont really belong on methods ( or we like to see on methods .. ) ?

    In addition there is the well established issue of not knowing what code will run and how the app is wired up, so you loose the quick learning curve and parsing of code to get to where you want.

    I think the proliferation of IOC is just because as developers we are too lazy in working out how to structure our apps so classes only have the minimum access needed. This is not much better than global statics. Maybe OO is just wrong and we should use SOA style coupling ..

    .Anyway im lost…

    Anyway if we persist with DI we should use small scopes for the container .

    maybe constructors should look like this Constructor ( subContainer , IMyCommonType)

    {

    }

    Ben

    • JonasGauffin

      I do agree with everything you say. However, I don’t blaim the container but a) the lazy developers b) container implementors that add too many features. A container applies to SRP too.

      I’ve also seen the pattern with users that think it’s OK to create a really big application just because they can do it in a loosely coupled fashion with the help of the container. It is, just as you say, better to create smaller applications using SOA or messaging. However, I would probably still use the container in them.

      As for the lifetime I always try to keep it short. When I use commands each lifetime spans over a command only. In windows services the lifetime is only when a new job is executed. In MVC it’s during the request. In winforms it’s over the command execution again.

      I do love to use an container, but it’s no magic bullet.

      • Scott

        “I don’t blaim the container but a) the lazy developers b) container implementors that add too many features.”
        I completely agree with this statement, especially the first part.
        Truth is, there is way too much hype around service locator being an anti-pattern and dependency injection frameworks (or other forms of dependency inversion) being a silver-bullet. It boils down to the fact that the human species likes to “take sides”, to become far to attached to one thing over another, to create camps of like-minded individuals with little tolerance for questioning the mental status quo (la cage aux folles).
        Software engineer, though creative, is fundamentally a science. It requires objective observation (never mind quantum mechanics for the moment) of functional and non-functional requirements. Then, after significant analysis, one should select the technologies (patterns, frameworks, platforms, etc) based on those requirements and not because “I like this pattern”, or so and so “said this pattern is an anti-pattern” just because, or any other bigoted view not based on actual fact. By fact, I mean that which can be reproduced time and time again yielding the same outcome. Technology is far too contextual! Not to mention it is always evolving.
        Bottom-line: IT individuals who state that any technology is a silver bullet are doomed to a limited existence and limited, even flawed outcomes. Call it laziness, or some other form of “ignore”-ance. It boils down to people becoming far too attached to a technology – as though it were their lover – which is kinda neurotic.
        I always say: “Consider everything in its context, including what I just said.” After all, are we not developing software for the purposes of doing business (directly or indirectly)…therefore…select the technologies that best match the requirements? (Rhetorical and IMHO)

  • Pingback: An IOC Container using Variadic Template - jSolutions Blog

  • Pingback: Wie sage ich es meinem (Service)Manager? - Zend Framework Magazin

  • Cygon

    I can’t follow your argumentation there.
    To me, the second example demonstrates even worse design that the first. It not only is a first class example of what makes service locator an anti-pattern (the User class is going shopping for services and without reading the code/docs, one wouldn’t have a clue which other services it accesses), it also combines it with global variables. A true dependency nightmare.
    Additionally
    – If you want to unit test that, you’d have to push your mocks into this ‘Global.Container’. That prevents multiple tests from running in parallel right there because only one mock can be active at the same time.
    – If you add an additional service dependency to your class, it will only blow up at runtime (or possibly even create a non-mocked instance of the service in unit tests)
    – You need to run binding setup code before your unit tests can run. Thus, in the strictest sense, you aren’t even able to unit test one class in isolation and you’re actually doing integration tests.
    – Your class now depends on one specific IoC implementation. Whereas with constructor-injected dependencies the class could be used without any IoC container.
    All possible uses of a service locator class promote the kind of bad design the two examples in your post show, that’s what makes it an anti-pattern.
    The replacement in ASP.NET MVC is straightforward constructor injection. Any ASP.NET MVC bridge for popular IoC containers offers constructor-injected controller factories. Scoping (singleton, thread, call, session) is easily configured through the bindings, unless you’re referring to something else.

    • http://blog.gauffin.org/ jgauffin

      Ehh. I don’t follow your comment at all? The example shown was to demonstrate where the pattern do not fit.
      ASP.NET MVC uses service location internally to allow devs to use constructor injection and that was my point. Without service location it would be impossible to do that.

  • C. Shea

    Your example of the use of Service Locator as not being an anti-pattern is exactly what Mark Seemann talks about in his book DI in .Net in terms of it being an anti-pattern. You are hiding the fact (from the compiler) that in order to use a User object, you need to have an instance of a IUserRepository and an ILogger. When instantiating a User from a third party component, the third party potentially has no idea that User requires an IUserRepository and an ILogger implementation. If you had used straight up DI and Constructer Injection, the third party would immediately know that User has a dependency on those interfaces and knows they must be provided (either statically or resolved through some container). Also, by using Service Locator, you are now spreading out calls to instantiate dependencies for the system across your system. There is no coherent view of what your system depends on. Also, there’s a chance that when you call the Service Locator to instantiate a dependency, that the locator has not been configured (yet) with that dependency, also causing brittleness. Also, it violates the Register, Resolve, Release pattern. There are no two ways about it. Service Locator is an anti-pattern. Everywhere Service Locator is used could be refactored to use DI instead, resulting in only one place where all dependencies are registered and resolved. If there’s a problem with the container, you know where to look–in the application seam, where your DI container is setup and called to resolve all dependencies needed by the application.

  • Pingback: Design patterns and practices in .NET: the Service Locator anti-pattern | Exercises in .NET with Andras Nemes