5

First, here's how I understand these two concepts: Service Locators are not Dependency Injection. Both Service Locators and Dependency Injection are applications of Inversion of Control. This is the understanding I reached after reading Martin Fowler's write-up on the topic. If my understanding is incorrect, please explain how.

In many places online, I have seen what are clearly Service Locators referred to as Dependency Injection libraries or frameworks. For example, Simple Injector calls itself "an open-source dependency injection (DI) library for .NET." However, in its quick start page, an example is shown which clearly demonstrates that Simple Injector is a Service Locator. Microsoft provides the .NET Core namespace "Microsoft.Extensions.DependencyInjection," which is clearly a Service Locator as well. An Essential .NET blog post from 2016 titled "Dependency Injection with .NET Core" explains in detail how to use the ".NET Core DI framework" to register services!

There are true (as I understand them) dependency injection containers around, of course, such as Ninject, which actually performs automated dependency injection.

Am I misunderstanding the distinction between these concepts? If not, how did they come to be so thoroughly mixed up?

1
  • The question is rooted on an overly granular interpretation to the point of forgetting that human speech is not rigorously and meticulously defined. When things are adjacent, the lines between them sometimes get a bit blurry. Disagree with that all you like and stick to your neat lines, that's perfectly fine. But just because you choose to do so does not mean that everyone else is going to choose to play by those same rules. I agree with all your precise definitions, but I think it's a fruitless endeavour to try and list every way in which someone on the internet might be wrong about that.
    – Flater
    9 hours ago

4 Answers 4

3

You've got to get the knowledge of your services into your framework, whether that be a "dependency injection" framework or a "service locator" framework, and you do that some variant of

framework.register(abstractType, concreteType)

no matter what framework you're using. The difference is in how you get things out of the framework again:

  • With a service locator, every time you want an instance of a service, you call framework.get(abstractType).
  • With dependency injection, you pass the dependencies down from one layer to the next, and let your framework do the job of wiring up those dependencies. (You may need a few calls to framework.get at the top level, but you shouldn't have one every time you want a service).

Certainly the latter is how Microsoft.Services.DependencyInjection is intended to be used, and it's not really any different from how NInject is used.

7
  • I'm not sure you're correct about Microsoft.Services.DependencyInjection being the latter. In the blog post that I linked, you can see that Application requests its dependency in the line Logger = Services.GetRequiredService<ILoggerFactory>.()CreateLogger<Application>();. This looks to me like a clear "service locator" paradigm. I do appreciate the point you and Christophe made (I believe you're saying the same thing) about both service locators and dependency injectors requiring a "service composer" component. Aug 23, 2020 at 15:40
  • 1
    You can absolutely use M.S.DI as a service locator if you want to, but it can certainly do "proper" DI as well. Aug 23, 2020 at 15:44
  • Do you have any examples of M.S.DI being used as a proper DI container? Would be very helpful Aug 23, 2020 at 15:45
  • 2
    @SnailCadet Straight from MS docs, here's the first thing I found by searching for .NET Core dependency injection example. As you can see, there's even an example with the Logger itself
    – gcali
    Aug 24, 2020 at 12:49
  • 1
    @SnailCadet What do you mean by "proper"? I mean, in a .NET Core web app the dependency injection framework is used to create a controller when a request is received; this is similar to what happens in other languages and frameworks, as far as I know. In other cases the usual flow is to use the Service Locator pattern for the root object; but it's not a weakness of .NET Core only, at some point all frameworks need to create a root object, in a web app that point is simply hidden by the framework with the construction of the controller. Care to give an example of how to avoid it in other cases?
    – gcali
    Aug 25, 2020 at 7:35
3

A first difference is: Not every service locator is a dependency injection container; a service locator can be used for another purpose than dependency injection. This can even create some issues such as hidden dependencies (see Fowler’s explanation on SL vs DI), to the point that some consider SL to be an anti-pattern (but again imho it depends on how it is used in the end).

A second and even more important difference is that dependency injection containers are more than just service locators: they are also service composers.

For example, in the SimpleInjector example to which you referred, you can see that the container is also informed about how to instantiate the service (singleton vs factory), and that it itself composes the service CancelOrderService, automatically resolving and injecting its known dependency with the help of the dependency map configured in the container. And this last feature is the real benefit of a DI framework that saves you from writing you a lot of boring and tedious boilerplate code every time you want to instantiate an object that relies on dependencies!

3
  • I appreciate the distinction you're making with "service composers." It's an (I think) nuanced bit that I missed in my research. You said that "Not every service locator is a dependency injection container." Do you have any examples of service locators that are also DI containers? Also, good point you make about CancelOrderService - I had misunderstood the example. On further review (correct me if I'm wrong), it looks like CancelOrderService is being constructed by the DI container when it is "service located" in main(). Aug 23, 2020 at 15:54
  • 1
    @SnailCadet Examples of locators that do not DI? There are for example a lot of ad-hoc locators that are used just to replace some global service objects and therefore only facilitate configuration with the risk of hidden couplings. In the same category you can find the service locators that act as proxy for remote web-services. Maybe we should add also to that categories the locators that can’t automatically compose services based on the dependency map? And yes, CancelOrderService is constructed by the DI container, avoiding you to manually inject the dependencies.
    – Christophe
    Aug 23, 2020 at 16:16
  • Agreed on "locators that can’t automatically compose services based on the dependency map" being a possibly separate category. Perhaps this is a biased view based on my background with "Pure" DI, but I think there is an important practical distinction between Service Locators that don't automatically compose services, and ones that do, the distinction being whether or not object dependencies are exposed via constructors or not. Hidden object dependencies (requiring review of documentation) are bad form compared to obvious dependencies in the constructor signature. Aug 24, 2020 at 18:18
2

Service location vs dependency injection

Service Locators are not Dependency Injection.

I disagree, but I think you intend to say/focus on something different than what I'm disagreeing with.

First of all, Philip Kendall's answer is correct that abstract-to-concrete type registration is the same in either case, the only real difference is how to access those registrations.

Internally, a DI framework uses a service locator to find the injectable instance/type. In essence, a service locator is the dictionary that contains the abstract-to-concrete type registrations that have been registered. Logically, any DI framework is required to keep track of those registrations so that it can then retrieve them when necessary.

Why are Service Locator frameworks often called Dependency Injection Containers?

What you call Dependency Injection is really just Service Location, but with the added feature of automatically locating services based on a constructor signature1 and acting as a factory for all of its registered types, instead of forcing the developer (= user of your framework) to directly request the services from your framework's service locator and being required to manually construct the dependency graph.

Note: whether the developer locates services inside the constructor body, or calls the constructor manually after having located the services, is an irrelevant distinction here. In either case, they've had to manually construct the dependency graph by supplying the services to classes that depend on them.

So the short answer to your question is "because DI frameworks are essentially service locators with a few extra features that abstract the location of registered services".


Caveat

1 Due to an objection raised in the comments, I agree that DI can be done without a service locator, but I have yet to come across a single DI framework that does so. I suspect doing DI as a framework without SL is going to put so much effort on the developer that the framework doesn't really add meaningful value anymore.

I'd be interested in seeing an example of DI without SL in a DI framework.

Since this question focuses on DI frameworks and what we call them; I stand by my claim within the context that the question defines.

10
  • 2
    @SnailCadet: "This feature is the distinction between DI and SL as I understand it." My point is that they are not distinctly different (i.e. completely different and unrelated things), but rather than one (DI) is a derivation of the other (SL). The constructor signatur argument is an implementation detail. It is not the driving factor leading you to decide between DI or SL , it's the other way around: deciding between DI/SL leads to needing a specific kind of constructor implementation. Architecture comes before implementation, otherwise your priorities get muddied.
    – Flater
    Aug 24, 2020 at 13:26
  • 2
    One can use dependency injection without a framework, and also without a service locator. When building a DI framework to automate the dependency resolution, you may use a service locator to do so (and that's most common), but you don't have to. But here's the biggest difference to me: If you were to describe a system as having been built with a service locator, I would assume you mean no DI. If you describe a system as having been built with a DI framework, I wouldn't care whether the resolution mechanism is a service locator or something else. They are two different architectural styles.
    – Eric King
    Aug 24, 2020 at 17:54
  • 2
    @EricKing: I agree that when you tell me you use SL, I'd infer you use SL and nothing more, but that reasoning simply does not hold up in logical terms. That's a human convention, not a logical conclusion. So I have no issue with statements like "I use SL instead of DI", but I still consider most (if not all, at least the ones I've seen) DI frameworks to internally use some sort of service location. The external contract to the consumer might not reveal it (though .Net Core certainly exposes an IServiceProvider when you want it to), but it's in there.
    – Flater
    Aug 24, 2020 at 22:59
  • 3
    @Flater I just mean that "Service Locator" is a loaded term... It has more than one meaning. It can describe an architectural pattern, and it can describe a type of class construct. Sure, many (most?) DI frameworks might incidentally use a SL class as the resolver, but that's very different from saying that a codebase uses a "service locator pattern" (where the consumer pulls in its dependencies), which is practically the opposite of Dependency Injection (where the consumer gets the dependencies pushed into it). So in at least that respect, DI and SL are quite distinct.
    – Eric King
    Aug 24, 2020 at 23:27
  • 2
    @EricKing: The question is why people conflate the names for SL and DI frameworks, not design patterns which these frameworks are an example of. Given the high tendency for DI frameworks to depend on SL, the names get conflated. Human nomenclature isn't always as clean as you'd like it to be. I don't disagree about the points you're making but that doesn't stop people from naming DI frameworks service locators or vice versa.
    – Flater
    Aug 24, 2020 at 23:30
0

The only difference between a Service Locator library and a Dependency Injection library is their intended use case.

In terms of how they are implemented in code, a Service Locator and a Dependency Injection Container can be completely identical. Both are, at their core, containers from which various instances can be pulled out.

What differentiates a DI container from a service locator is how they are used:

  1. When using the service locator pattern, a client directly asks the service locator to provide a service to it.
  2. When using the dependency injection pattern, an injector injects a service to the client, without the client being aware of the injector class at all, nor from where the service is coming from.

A Service Locator library would likely be optimized around it being really easy to request services, since that would be something that would be expected to be done all over the codebase with it. It's quite likely that the service locator would be a static class, or a singleton, to make it easily accessible from anywhere.

Service.Set<TService>(TService service);
Service.Get<TService>();

A Dependency Injection container on the other hand would likely be optimized around it being really easy to initialize clients, with all their dependencies getting automatically injected to them.

container.Register<TService, TConcrete>();
container.GetInstance<TClient>();

A Dependency Injection Container often isn't meant to be referenced at all outside of a singular location, the composition root, so making it easily accessible to many clients is likely not a priority.

Simple Injector offers the functionality to create a new client object, and have all its dependencies get automatically resolved and delivered to its constructor as arguments. This is clearly dependency injection specific functionality, so labeling it as a Dependency Injection library makes perfect sense.

New contributor
Sisus is a new contributor to this site. Take care in asking for clarification, commenting, and answering. Check out our Code of Conduct.
1
  • 1
    +1 for "A Dependency Injection Container often isn't meant to be referenced at all outside of a singular location" Yes, you can use/abuse most any DI container as a service locator just by referencing it all over the place rather than asking for your dependencies in a constructor or methods argument list. Martin Fowler contrasted them here. yesterday

Not the answer you're looking for? Browse other questions tagged or ask your own question.