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);
}
}
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>>();
}
}
Wrapping up
Referencing the container is definitely not the Service Locator Anti-pattern if you stick to the golden rule.
Enjoy!
@qujck
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.
My advice would be to inject the queries and commands directly.
Consider the following 2 examples
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.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.
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 theContainer
then that class (such as your Facade) should be defined as aprivate
class within your Composition Root.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:
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.
Hi @Korimato,
I feel that the way you are using the container here seems a little bit fragile. I would prefer to see
FindPostByIdDbCommand
andFindPostsByCriteriaDbCommand
injected into the constructor ofPostsGateway
. Having the dependencies explicitly listed and injected in would not only remove the dependency on the container; it would also makePostsGateway
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?
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?
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?