Referencing the container is not automatically the Service Locator Anti-pattern

This post will briefly describe when it is ok to reference a container in your application.

What is a Container?

A container is an object that you delegate the responsibility of creating and managing your object graphs and object lifetimes.

What is a Service?

A Service is an object that exposes one or more methods.

What is the Service Locator Anti-pattern?

The best description of Service Locator Anti-pattern can be found on Mark Seemann’s blog here.

A common example is a central, global, static reference to a container that is accessible from anywhere in the code. The service locator is used to find instances of services. Your code can reference this service locator from anywhere and can call into it at any time.

E.g.:

public class BusinessObject {
    public void Method() {
        var service = ServiceLocator.Resolve<IService>();
    }
}

Code that references the service locator cannot run without the service locator and the service locator hides a classes dependencies.

If you’re not supposed to reference the container all over the place how do you resolve dependencies within your classes?

You resolve dependencies using the Dependency Inversion Principle; injecting dependencies into each object.

Surely you must have some references to the container?

You have to reference the container to configure it and to Resolve() instances from it. You have to do some Service Locator type activity and there is no escape from that fact.

Frameworks such as Microsoft’s MVC framework hide the fact that the container is acting as a service locator.

IDependencyResolver

Defines the methods that simplify service location and dependency resolution.

You cannot avoid Service Location; you can carefully govern and control when and where it happens.

Where is it ok to reference the container?

You can reference the container anywhere in the Composition Root

What is the Composition Root?

The composition root is the logical place that you configure the container.

A common misconception is that the Composition Root has to be in one file. This is not strictly true, but it does need to be logically separated from the rest of your solution.

  • It can be spread across multiple files
  • It can be a folder filled with classes
  • It can be a namespace filled with classes
  • It should contain all the code that references the container

As Mark Seemann advises here, the Composition Root should be

As close as possible to the application’s entry point.

When is it ok to reference the container?

The main driver for needing a hard reference to the container is to dynamically resolve objects based on data that is only known at run-time.

As mentioned already an example of this is the MVC framework that will resolve an object graph for each request based on the route of the request.

The Golden Rule

A class that references the container should not return a service. As stated above a service is a class that exposes one or more methods. A class that references the container should return the result of one or more service method calls or nothing (e.g. void, null, etc.).

Sticking to this rule effectively means your classes are acting as a proxy.

If your class references the container and returns a service then it is more akin to a factory and may be acting as a Service Locator.

What does a good example look like?

public sealed class EventPublisher : IEventPublisher {
    private readonly Container container;

    public EventPublisher(Container container) {
        this.container = container;
    }

    public void Publish<TEvent>(TEvent eventMessage) where TEvent : class, IEvent {
        var subscriber = container.GetInstance<ISubscriber<TEvent>>();
        subscriber.Handle(eventMessage);
    }
}

Another good example?

sealed class QueryProcessor : IQueryProcessor {
    private readonly Container container;

    public QueryProcessor(Container container) {
        this.container = container;
    }

    public TResult Process<TResult>(IQuery<TResult> query) {
        var handlerType = typeof(IQueryHandler<,>).MakeGenericType(query.GetType(), typeof(TResult));
        dynamic handler = container.GetInstance(handlerType);
        return handler.Handle((dynamic)query);
    }
}

source

What does a mistake look like?

public class LogResolverService : ILogResolverService {
    private readonly Container container;

    public LogResolverService(Container container) {
        container = container;
    }

    public ILogger<T> Resolve<T>() {
        return this.container.GetInstance<ILogger<T>>();
    }
}

source

Wrapping up

Referencing the container is definitely not the Service Locator Anti-pattern if you stick to the golden rule.

Enjoy!

@qujck

  8 comments for “Referencing the container is not automatically the Service Locator Anti-pattern

  1. korimato
    2nd May 2015 at 7:40 pm

    Actually I have come to use 2-3 commands per class and normally they belong to different repositories. If I have 5 I try to refactor.

    All these questions I have made here came because when I saw for the first time the class I put before (PostsGateway) I thought it was a good way of encapsulate several operations, in this case DBCommands, in the same place and without the need of convert the Gateway on a huge class with a lot of lines of code by having the implementation of each of its methods distributed into different classes. It looks me great having a facade that provides me a lot classes implementations behind in a simple method call.

    But If it really is a bad way to use the container, I guess I forget to use it in this way and inject directly db commands in the class.

    • Peter
      3rd May 2015 at 9:24 am

      My advice would be to inject the queries and commands directly.

      Consider the following 2 examples

      public class Service1
      {
          public Service1(
              FindPostByIdDbCommand findById,
              UpdatePostDbCommand update)
          {
          }
      }
      
      public class Service2
      {
          public Service2(PostGateway gateway)
          {
          }
      }
      

      You can instantly see Service1‘s dependencies and have a good understanding of the object graph. Service2 does not tell us so much and we would need to read through the code and figure out the dependencies.

  2. korimato
    29th April 2015 at 7:13 pm

    Hi! I have found your article because I’m a little confused about the topic of consider inject service locator as an anti-pattern. I have read in a lot web sites this afirmation but others say the opposite. You put a use case of good use of service locator but I don’t use like you. For example, I have a lot db commands related with an entity (InsertUserDbCommad, EditUserDbCommand, SearchUserByCriteriaDbCommand…) but to avoid to inject each single class where I want, I have on a Facade class where I have method where container creates the correct db command and executes. Is it a good use of the service container? Are there other use cases of it? Thanks in advance.

    • Peter
      29th April 2015 at 8:29 pm

      Hi @Korimato, what you are describing sounds a lot like the QueryProcessor I have shown above. All I am really saying is that if you do have a class that references the Container then that class (such as your Facade) should be defined as a private class within your Composition Root.

      • korimato
        30th April 2015 at 6:28 pm

        Thanks a lot for your reply and sorry a lot for late to answer!

        I think I’m understanding this more a more. Internet some times is very confused and it’s difficult find the good articles.

        If you do not mind I would like to use a little example (takes very little time to see) to illustrate this. Returning to the example I put yesterday, I have the following class:

        <?php
        
            namespace Project\infrastructure\gateway\posts;
        
            use Auryn\Provider;
            use Project\domainmodel\PostsSearchCriteria;
            use Project\domainservices\post\IPostsGateway;
        
            class PostsGateway implements IPostsGateway
            {
        
                private $injector;
        
                public function __construct(Provider $injector)
                {
                    $this->injector = $injector;
                }
        
                /**
                 * @param $id
                 * @return \Project\domainmodel\Post
                 */
                public function findPostById($id)
                {
                    /** @var $obj FindPostByIdDbCommand */
                    $obj = $this->injector->make('Project\infrastructure\gateway\posts\FindPostByIdDbCommand');
                    return $obj->find($id);
                }
        
                /**
                 * @param PostsSearchCriteria $criteria
                 * @return \Project\domainmodel\Post[]|void
                 */
                public function findPostsByAdvancedCriteria(PostsSearchCriteria $criteria)
                {
                    /** @var FindPostsByCriteriaDbCommand $obj */
                    $obj = $this->injector->make('Project\infrastructure\gateway\posts\FindPostsByCriteriaDbCommand');
                    return $obj->find($criteria);
                }
            }
        
        ?>
        

        http://www.codeshare.io/rF1xo

        As you can see, I inject on it the container. The “QueryProcessor” you suggested is perfect in this case but I would like to follow with this example. Then, from what I understand, this class is perfect valid. It does not violate the use of the container WHENEVER I put this class on composition root folder. Not? Meanwhile, the interface “IPostsGateway” I would have it on the “regular” project structure, in this case Project/domain/services/. Is it correct?

        Sorry my long message. I hope not steal you too time.

        • Peter
          30th April 2015 at 9:32 pm

          Hi @Korimato,

          I feel that the way you are using the container here seems a little bit fragile. I would prefer to see FindPostByIdDbCommand and FindPostsByCriteriaDbCommand injected into the constructor of PostsGateway. Having the dependencies explicitly listed and injected in would not only remove the dependency on the container; it would also make PostsGateway easier to reason about (i.e. figure out what dependencies it has and therefore what it might be doing) and simpler to unit test.

          Probably the easiest way to decide if you are misusing the container would be to count the number of classes you have like PostsGateway that take a hard reference to the container. If it is more than one or two then I would advise you to find another way to solve you problem.

          When a class references the container you need to read every line of code to figure out any dependencies it may have. When you inject all your dependencies into the the constructor it is really easy to tell what depends on what.


          About 3 years ago I stumbled across these two great articles (here and here) and they forever changed the way I write code. Maybe they will help you too?

        • korimato
          1st May 2015 at 5:59 pm

          I agree that we should move in the constructor the dependencies we use however this class, PostsGateway , is slated to grow much in its constructor as incorporating more and more dbcommands. For now, I have “FindPostByIdDbCommand” and “FindPostsByCriteriaDbCommand” but I also will have “InsertPostDbCommand”, “UpdatePostDbCommand”, “FindPostsByAuthor”, “FindPostsPendingToPublishDbCommand”…

          This leads into constructor over injection. The solution is to implement the “IQueryProcessor” and the solutions of the two blog articles you put, nevertheless it seemed natural to have a “PostsGateway”, “UsersGateway”, “TagsGateway”, “CategoriesGateway”, “OptionsGateway”… But your words “Probably the easiest way to decide if you are misusing the container would be to count the number of classes you have like” seems that I’m violating this.

          I also recognize that I have been a bit driven by this presentation: http://www.slideshare.net/kindblad/application-architecture-april-2014 The pages 26 and 35 show use cases where we can use a container as dependency. What do you think about this author say? In the page 38 insists that the container should only be used on the DependencyResolutionLayer, or Composition Root.

          So, if I have a lot classes that would have the container in the constructor (“PostsGateway”, “UsersGateway”, “TagsGateway”, “CategoriesGateway”, “OptionsGateway” or maybe other kind or class), should I rethink the problem?

          • Peter
            2nd May 2015 at 4:10 pm

            I have to ask a question: I assume you have some form of services that reference your repositories (the ...gateway classes) and execute queries or run commands? If so, do the majority of those service classes require more than say 3 to 5 of the actions that your repositories expose?

Leave a Reply