Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed last month.
The community reviewed whether to reopen this question last month and left it closed:
Original close reason(s) were not resolved
Improve this question
Recently I've read Mark Seemann's article about Service Locator anti-pattern.
Author points out two main reasons why ServiceLocator is an anti-pattern:
API usage issue (which I'm perfectly fine with)
When class employs a Service locator it is very hard to see its dependencies as, in most cases, class has only one PARAMETERLESS constructor.
In contrast with ServiceLocator, DI approach explicitly exposes dependencies via constructor's parameters so dependencies are easily seen in IntelliSense.
Maintenance issue (which puzzles me)
Consider the following expample
We have a class 'MyType' which employs a Service locator approach:
public class MyType
{
public void MyMethod()
{
var dep1 = Locator.Resolve<IDep1>();
dep1.DoSomething();
}
}
Now we want to add another dependency to class 'MyType'
public class MyType
{
public void MyMethod()
{
var dep1 = Locator.Resolve<IDep1>();
dep1.DoSomething();
// new dependency
var dep2 = Locator.Resolve<IDep2>();
dep2.DoSomething();
}
}
And here is where my misunderstanding starts. The author says:
It becomes a lot harder to tell whether you are introducing a breaking change or not. You need to understand the entire application in which the Service Locator is being used, and the compiler is not going to help you.
But wait a second, if we were using DI approach, we would introduce a dependency with another parameter in constructor (in case of constructor injection). And the problem will be still there. If we may forget to setup ServiceLocator, then we may forget to add a new mapping in our IoC container and DI approach would have the same run-time problem.
Also, author mentioned about unit test difficulties. But, won't we have issues with DI approach? Won't we need to update all tests which were instantiating that class? We will update them to pass a new mocked dependency just to make our test compilable. And I don't see any benefits from that update and time spending.
I'm not trying to defend Service Locator approach. But this misunderstanding makes me think that I'm losing something very important. Could somebody dispel my doubts?
UPDATE (SUMMARY):
The answer for my question "Is Service Locator an anti-pattern" really depends upon the circumstances. And I definitely wouldn't suggest to cross it out from your tool list. It might become very handy when you start dealing with legacy code. If you're lucky enough to be at the very beginning of your project then the DI approach might be a better choice as it has some advantages over Service Locator.
And here are main differences which convinced me to not use Service Locator for my new projects:
Most obvious and important: Service Locator hides class dependencies
If you are utilizing some IoC container it will likely scan all constructor at startup to validate all dependencies and give you immediate feedback on missing mappings (or wrong configuration); this is not possible if you're using your IoC container as Service Locator
For details read excellent answers which are given below.
If you define patterns as anti-patterns just because there are some situations where it does not fit, then YES it's an anti pattern. But with that reasoning all patterns would also be anti patterns.
Instead we have to look if there are valid usages of the patterns, and for Service Locator there are several use cases. But let's start by looking at the examples that you have given.
public class MyType
{
public void MyMethod()
{
var dep1 = Locator.Resolve<IDep1>();
dep1.DoSomething();
// new dependency
var dep2 = Locator.Resolve<IDep2>();
dep2.DoSomething();
}
}
The maintenance nightmare with that class is that the dependencies are hidden. If you create and use that class:
var myType = new MyType();
myType.MyMethod();
You do not understand that it has dependencies if they are hidden using service location. Now, if we instead use dependency injection:
public class MyType
{
public MyType(IDep1 dep1, IDep2 dep2)
{
}
public void MyMethod()
{
dep1.DoSomething();
// new dependency
dep2.DoSomething();
}
}
You can directly spot the dependencies and cannot use the classes before satisfying them.
In a typical line of business application you should avoid the use of service location for that very reason. It should be the pattern to use when there are no other options.
Is the pattern an anti-pattern?
No.
For instance, inversion of control containers would not work without service location. It's how they resolve the services internally.
But a much better example is ASP.NET MVC and WebApi. What do you think makes the dependency injection possible in the controllers? That's right -- service location.
Your questions
But wait a second, if we were using DI approach, we would introduce a
dependency with another parameter in constructor (in case of
constructor injection). And the problem will be still there.
There are two more serious problems:
With service location you are also adding another dependency: The service locator.
How do you tell which lifetime the dependencies should have, and how/when they should get cleaned up?
With constructor injection using a container you get that for free.
If we may
forget to setup ServiceLocator, then we may forget to add a new
mapping in our IoC container and DI approach would have the same
run-time problem.
That's true. But with constructor injection you do not have to scan the entire class to figure out which dependencies are missing.
And some better containers also validate all dependencies at startup (by scanning all constructors). So with those containers you get the runtime error directly, and not at some later temporal point.
Also, author mentioned about unit test difficulties. But, won't we have issues with DI approach?
No. As you do not have a dependency to a static service locator. Have you tried to get parallel tests working with static dependencies? It's not fun.
I would also like to point out that IF you are refactoring legacy code that the Service Locator pattern is not only not an anti-pattern, but it is also a practical necessity. No-one is ever going to wave a magic wand over millions of lines of code and suddenly all that code is going to be DI ready. So if you want to start introducing DI to an existing code base it is often the case that you will change things to become DI services slowly, and the code that references these services will often NOT be DI services. Hence THOSE services will need to use the Service Locator in order to get instances of those services that HAVE been converted to use DI.
So when refactoring large legacy applications to start to use DI concepts I would say that not only is Service Locator NOT an anti-pattern, but that it is the only way to gradually apply DI concepts to the code base.
From the testing point of view, Service Locator is bad. See Misko Hevery's Google Tech Talk nice explanation with code examples http://youtu.be/RlfLCWKxHJ0 starting at minute 8:45. I liked his analogy: if you need $25, ask directly for money rather than giving your wallet from where money will be taken. He also compares Service Locator with a haystack that has the needle you need and knows how to retrieve it. Classes using Service Locator are hard to reuse because of it.
Maintenance issue (which puzzles me)
There are 2 different reasons why using service locator is bad in this regard.
In your example, you are hard-coding a static reference to the service locator into your class. This tightly couples your class directly to the service locator, which in turns means it won't function without the service locator. Furthermore, your unit tests (and anybody else who uses the class) are also implicitly dependent on the service locator. One thing that has seemed to go unnoticed here is that when using constructor injection you don't need a DI container when unit testing, which simplifies your unit tests (and developers' ability to understand them) considerably. That is the realized unit testing benefit you get from using constructor injection.
As for why constructor Intellisense is important, people here seem to have missed the point entirely. A class is written once, but it may be used in several applications (that is, several DI configurations). Over time, it pays dividends if you can look at the constructor definition to understand a class's dependencies, rather than looking at the (hopefully up-to-date) documentation or, failing that, going back to the original source code (which might not be handy) to determine what a class's dependencies are. The class with the service locator is generally easier to write, but you more than pay the cost of this convenience in ongoing maintenance of the project.
Plain and simple: A class with a service locator in it is more difficult to reuse than one that accepts its dependencies through its constructor.
Consider the case where you need to use a service from LibraryA that its author decided would use ServiceLocatorA and a service from LibraryB whose author decided would use ServiceLocatorB. We have no choice other than using 2 different service locators in our project. How many dependencies need to be configured is a guessing game if we don't have good documentation, source code, or the author on speed dial. Failing these options, we might need to use a decompiler just to figure out what the dependencies are. We may need to configure 2 entirely different service locator APIs, and depending on the design, it may not be possible to simply wrap your existing DI container. It may not be possible at all to share one instance of a dependency between the two libraries. The complexity of the project could even be further compounded if the service locators don't happen to actually reside in the same libraries as the services we need - we are implicitly dragging additional library references into our project.
Now consider the same two services made with constructor injection. Add a reference to LibraryA. Add a reference to LibraryB. Provide the dependencies in your DI configuration (by analyzing what is needed via Intellisense). Done.
Mark Seemann has a StackOverflow answer that clearly illustrates this benefit in graphical form, which not only applies when using a service locator from another library, but also when using foreign defaults in services.
My knowledge is not good enough to judge this, but in general, I think if something has a use in a particular situation, it does not necessarily mean it cannot be an anti-pattern. Especially, when you are dealing with 3rd party libraries, you don't have full control on all aspects and you may end up using the not very best solution.
Here is a paragraph from Adaptive Code Via C#:
"Unfortunately, the service locator is sometimes an unavoidable anti-pattern. In some application types— particularly Windows Workflow Foundation— the infrastructure does not lend itself to constructor injection. In these cases, the only alternative is to use a service locator. This is better than not injecting dependencies at all. For all my vitriol against the (anti-) pattern, it is infinitely better than manually constructing dependencies. After all, it still enables those all-important extension points provided by interfaces that allow decorators, adapters, and similar benefits."
-- Hall, Gary McLean. Adaptive Code via C#: Agile coding with design patterns and SOLID principles (Developer Reference) (p. 309). Pearson Education.
I can suggest considering generic approach to avoid the demerits of Service Locator pattern.
It allows explicitly declaring class dependencies and substitute mocks and doesn't depend on a particular DI Container.
Possible drawbacks of this approach is:
It makes your control classes generic.
It is not easy to override some particular interface.
1 First Declare interface
public interface IResolver<T>
{
T Resolve();
}
Create ‘flattened’ class with implementing of resolving the most of frequently used interfaces from DI Container and register it.
This short example uses Service Locator but before composition root. Alternative way is inject each interface with constructor.
public class FlattenedServices :
IResolver<I1>,
IResolver<I2>,
IResolver<I3>
{
private readonly DIContainer diContainer;
public FlattenedServices(DIContainer diContainer)
{
this.diContainer = diContainer;
}
I1 IResolver<I1>.Resolve()
=> diContainer.Resolve<I1>();
I2 IResolver<I2>.Resolve()
=> diContainer.Resolve<I2>();
I3 IResolver<I3>.Resolve()
=> diContainer.Resolve<I3>();
}
Constructor injection on some MyType class should look like
public class MyType<T> : IResolver<T>
where T : class, IResolver<I1>, IResolver<I3>
{
T servicesContext;
public MyType(T servicesContext)
{
this.servicesContext = servicesContext
?? throw new ArgumentNullException(nameof(serviceContext));
_ = (servicesContext as IResolver<I1>).Resolve() ?? throw new ArgumentNullException(nameof(I1));
_ = (servicesContext as IResolver<I3>).Resolve() ?? throw new ArgumentNullException(nameof(I3));
}
public void MyMethod()
{
var dep1 = ((IResolver<I1>)servicesContext).Resolve();
dep1.DoSomething();
var dep3 = ((IResolver<I3>)servicesContext).Resolve();
dep3.DoSomething();
}
T IResolver<T>.Resolve() => serviceContext;
}
P.S. If you don't need to pass servicesContext further in MyType, you can declare object servicesContext; and make generic only ctor not class.
P.P.S. That FlattenedServices class could be considered as main DI container and a branded container could be considered as supplementary container.
The Author reasons that "the compiler won't help you" - and it is true.
When you deign a class, you will want to carefully choose its interface - among other goals to make it as independent as ... as it makes sense.
By having the client accept the reference to a service (to a dependency) through explicit interface, you
implicitly get checking, so the compiler "helps".
You're also removing the need for the client to know something about the "Locator" or similar mechanisms, so the client is actually more independent.
You're right that DI has its issues / disadvantages, but the mentioned advantages outweigh them by far ... IMO.
You're right, that with DI there is a dependency introduced in the interface (constructor) - but this is hopefully the very dependency that you need and that you want to make visible and checkable.
Yes, service locator is an anti-pattern it violates encapsulation and solid.
Service Locator(SL)
Service Locator solves [DIP + DI] issue. It allows by interface name satisfy needs. Service Locator can be as singleton or can be passed into constructor.
class A {
IB ib
init() {
ib = ServiceLocator.resolve<IB>();
}
}
The problem here that it is not clear which exactly classes(realizations of IB) are used by client(A).
proposal - pass parameter explicitly
class A {
IB ib
init(ib: IB) {
self.ib = ib
}
}
SL vs DI IoC Container(framework)
SL is about saving instances when DI IoC Container(framework) is more about creating instances.
SL works as a PULL command when it retrieves dependencies inside constructor
DI IoC Container(framework) works as a PUSH command when it put dependencies into constructor
I think that the author of the article shot himself on the foot in proving that it's an anti pattern with the update written 5 years later. There, it is said that this is the correct way:
public OrderProcessor(IOrderValidator validator, IOrderShipper shipper)
{
if (validator == null)
throw new ArgumentNullException("validator");
if (shipper == null)
throw new ArgumentNullException("shipper");
this.validator = validator;
this.shipper = shipper;
}
Then below is said:
Now it's clear that all three object are required before you can call the Process method; this version of the OrderProcessor class advertises its preconditions via the type system. You can't even compile client code unless you pass arguments to constructor and method (you can pass null, but that's another discussion).
Let me stress the last part again:
you can pass null, but that's another discussion
Why that is another discussion? That is a huge deal. An object that receives its dependencies as arguments fully depends on the previous execution of the application (or tests) to provide those objects as valid references/pointers. It is not "encapsulated" in the terms that the author expressed, as it depends on a lot of external machinery to run in a satisfactory manner for the object to be constructed at all, and later to work properly when it needs to use the other class.
The author claims that it's the Service Locator which is not encapsulated because it's depending on an additional object that you can't isolate from on the tests. But that other object could very well be a trivial map or vector, so it's pure data with no behavior. In C++, for example, containers are not part of the language, so you rely on containers (vectors, hash maps, strings, etc.) for all non-trivial classes. Are they not isolated because rely on containers? I don't think so.
I think that both using manual dependency injection or a service locator the objects are not really isolated from the rest: they need their dependencies, yes or yes, but are provided in a different way. I for one think that a locator even helps with the DRY principle, as it's error prone and repetitive to pass over and over pointers through the application. The service locator can also be more flexible in that an object might retrieve its dependencies when needed (if needed), not only via the constructor.
The problem of the dependencies not being explicit enough via the constructor of the object (on an object using the service locator) is solved by the very thing I stressed out before: passing null pointers. It can be even used to mix and match both systems: if the pointer is null, use the service locator, otherwise, use the pointer. Now it is enforced via the type system, and it's obvious to the user of the class. But we can do even better.
One additional solution that is surely doable with C++ (I don't know about Java/C#, but I suppose it could be done as well), is to write a helper class to be instantiated like LocatorChecker<IOrderValidator, IOrderShipper>. That object could check on it's constructor/destructor that the service locator holds a valid instance of the required classes, hence, being also less repetitive than the example provided by Mark Seeman.
Is there a way to instantiate a class without a constructor if I don't have a handle to the container?
If I call container.RegisterType<IMyClass , MyClass>() I know I can use unity to instantiate an object in a constructor.
Someclass(IMyClass myClass)
var s = new Someclass();
I also know I can use
container.Resolve<IMyClass>() outside a constructor if I have a handle to the container, or use the DependencyFactory, which is also the same thing.
If I am writing code for a large project that doesn't save a handle to the container, and it is not appropriate to use a constructor, is there a way to instatiate class using unity?
you should not be referencing the container in your classes. You container should be orchestrating the construction of the object graph and your class should not be calling it, it should be calling your classes.
Ideally your container should not be used outside of the Composition Root. See this answer
The point I (and Belogix) was trying to make (not very well it seems) is that you should never need to create dependent objects directly if you are using DI correctly. Passing the container around is a code smell and you should avoid this if at all possible (which it almost always is). If you require an instance of a class in a place where you 'don't have a handle to the container' you should be asking for an instance of that class through your object's constructor. Doing this allows the IoC container to know that your object has a dependency and it can then supply an instance of that dependency when the container creates an instance of the class. If you follow this principal with every dependency all the way up your chain then your composition root becomes the only place that you need to create your objects, and you can do it manually (poor man's DI), or you can configure a container to do it for you.
I suggest you read this post it really helped me understand the concept of a composition root and why not leaking your container throughout the application is a Good Idea.
If you want to create an object without calling the constructor and without a handle to the container then you can use GetUnitializedObject as outlied in this answer but you have to ask yourself, if you are swimming that hard upstream to create your objects, surely there must be a better way?
I was only trying to point out what I consider the currently accepted best practices around using a container.
Background
I'm using Castle Windsor as my IOC container in a WPF application. In this application, the user can open a single project file, which is modeled using a concrete version of an IProjectModel interface. So, at any given time there is zero or one instance(s) of IProjectModel available. I'm currently defining the lifestyle of its implementor as transient, and this implementor expects in its constructor a filename as a string which is chosen by the user (from a dialog). The IProjectModel instance is resolved via a typed factory interface, e.g.:
public interface IProjectModelFactory
{
IProjectModel Create(string fileName);
}
Question
I initially figured it was bad to treat it as a singleton since:
it is transient with respect to the application lifetime;
it has dependencies of its own, i.e. the filename (string) to open, that I don't think I could specify if it had singleton/scoped lifestyle;
passing it around keeps open the option of having multiple projects open at once.
However, now that I'm creating factory after factory in order to pass the current IProjectModel instance around I'm somewhat regretting that decision. It'd be much easier to have the container hand my objects the current project model, rather than pass it down from way up the object chain.
How is a situation like this supposed to be handled using Castle Windsor?
It seems like the Scoped Lifestyle is built for this (the scope is the currently open project/file name), but I can't figure out how to get information about the opened file into the IScopeAccessor since I can't inject anything into that.
IProjectModel sounds like it contains data--i.e. it's not a pure service.
Consider modeling it like you would model a service that was backed by a database, but instead of connecting to a database, use some in-memory construct. It's probably as simple as a static member variable on your service implementation. Something like:
public class ProjectDataService : IProjectDataService
{
private static IProjectModel _projectModel;
public IProjectModel Create(string fileName)
{
if (_projectModel == null)
{
//create it
}
return _projectModel;
}
}
(Note that you you may have to do some locking of the member variable.)
Now if you need to switch to having multiple projects open at once, change your member variable to a list structure (IList, Dictionary, etc.).
Edit based on your comment.
I'm referring to once it's already been created. The big idea behind IOC seems to be "let the container handle the dependencies", and it seems Windsor could support this, I just don't see how. I'd like to specify IProjectModel in a transient object's constructor, and have the container resolve the current IProjectModel, if there is one. Your answer is a lazy singleton, which isn't what I was asking for.
What I'm saying is IProjectModel is not really a service--it's state/data. So injecting it directly doesn't make sense (at least not to me). Wrapping it in a IProjectModel data service or IProjectModel "state manager" is more in line with injecting services, which is what DI frameworks generally do.
Can you register an IProjectModel? Yes. However, container registration is generally done at application bootstrap time, not based on user input. Also, from your description, you may need to support multiple instances of IProjectModel. How would the container know which instance to give to you when you ask for it?
As a more obvious example: would you consider injecting a string or an int in your constructor?
Let the container handle the dependencies is not exactly how I would describe the "big idea" behind IOC. It's about decoupling from (or handling) service dependencies. So if you want to inject something that is stateful, I'm suggesting you wrap that state in a class that can be injected like a service.
I'm trying to learn dependency injection, and there are many subtleties to it I'm yet to grasp. One of the books that I've started reading for that purpose is "Foundations of Programming" by Karl Seguin. There's an example about dependency injection:
public class Car
{
private int _id;
public void Save()
{
if (!IsValid())
{
//todo: come up with a better exception
throw new InvalidOperationException("The car must be in a valid state");
}
IDataAccess dataAccess = ObjectFactory.GetInstance<IDataAccess>();
if (_id == 0)
{
_id = dataAccess.Save(this);
}
else
{
dataAccess.Update(this);
}
}
}
And then he goes ahead and suggest adding another level of indirection, rather than calling ObjectFactory directly in the method:
public static class DataFactory
{
public static IDataAccess CreateInstance
{
get
{
return ObjectFactory.GetInstance<IDataAccess>();
}
}
}
But isn't this "Service Location" in fact?
It is service locator. There are several of ways to use dependency:
aggregation (example case)
composition
DI in constructor, mandatory (could be injected using SL on upper level)
DI in property, optional (could be injected using SL on upper level)
What to choose depends on many factors, for example whether it is stable or unstable dependency, whether you need to mock it in tests or not etc. There is good book on DI called 'Dependency Injection in .NET' by Mark Seemann.
Yes, looks like SL to me. Dependency injection traditionally follows one of two patterns; property injection or constructor injection.
Dependency injection feels more effort than service location at first, but service location (SL) has a number of negatives. It is far too easy with a service locator to just go crazy requesting services on a whim, all over the place. This is fine until you go to refactor and realise the coupling is "too damn high".
With DI I prefer the constructor injection form because it forces me to think up front about who needs what.
That all said, my current project was started as a green field project using a service locator because it gave me the flexibility "not" to think about dependencies and to let the application shape evolve. Latterly I've been refactoring to use DI, mainly to get a handle on what relies on what and why.
Your example is ServiceLocator. There is always a ServiceLocator somewhere. I would say the key is to understanding why you would use it directly and why ideally you might not have to.
The key concept is the dependency inversion principal. Dependency injection and inversion of control frameworks are tools that facilitate application of the principal. Ideally you want your objects constructor parameters to be interface definitions which will be resolved at object creation time.
If you are using modern tools, such as asp.net MVC then you have access to what is called the composition root which is the entry point of the application. In MVC it's controller. Since you have access to the composition root you don't need to use ServiceLocator because injection is driven from the top for you by your IOC framework which you would have registered and setup. Basically your controller has constructors parameters like ISomeService which is registered with IOC and injected automatically when the controller instance is created. If the ISomeService had some dependencies they would also be in the constructor as ISomeUtility, and so forth as your objects get deeper and deeper. This is ideal and you would never have need to use the ServiceLocator to resolve an object.
If you were in a situation using technology that doesn't grant you access to the root or if you were wanting to start using an IOC framework in an application that didn't have one and you were adding it for the first time then you may find you can't get to the composition root. It could be a limitation of the framework or the quality of the code. In these cases you have to use the ServiceLocator or directly create the object yourself. In these cases using the ServiceLocator is OK and is better than creating that object yourself.
I'm using NInject on a new web application and there are two things that are unclear to me:
Don't I need to keep a reference to the Kernel around (Session/App variable) to insure that GC doesn't collect all my instances? For example, if I specify .Using() and then the Kernel object gets collected, aren't all my "singletons" collected as well?
If I do need keep a reference to a Kernel object around, how do I allow the arguments passed in to WithArguments() to change or is that not possible.
It's true that you don't want to pass around the kernel. Typically, in a web app, I store the kernel in a static property in the HttpApplication. If you need a reference to the kernel, you can just expose a dependency (via constructor argument or property) that is of the type IKernel, and Ninject will give you a reference to the kernel that activated the type.
If you use WithArguments() on a binding, they will be used for all activations. If you use IParameters, they will only be used for that activation. (However, if the service you're activating has a re-usable behavior like Singleton, it won't be re-activated even if you pass different IParameters.)
This is a common pitfall when starting to use a IoC container. See this related question.
In a nutshell:
It's bad practice to pass your container around (been there, done that, and it really hurts)
If you really need to invocate directly the container, first consider abstracting to an injected factory, then as a last resource consider using a static gateway to the container
Mark Seeman -- author of Manning Dependency Injection Suggust to Use Hollywood principle Don't call us(IOC framework) instead We will call you ... .. The IOC container should be placed in the Application's Composition root.. and it needs to instantiated as requested.. like wat nate mentioned
.. For the Web Application the Composition root is Global.asax file where the u can use the override the startup events and There u can bind your Ninject to resolve the component