It is considered that the Service Locator is an antipattern. But is it correct to get all the necessary dependencies in the constructor if they are used only under certain conditions?
Approach 1 (Service Locator)
public class MyType
{
public void MyMethod()
{
if (someRareCondition1)
{
var dep1 = Locator.Resolve<IDep1>();
dep1.DoSomething();
}
if (someRareCondition2)
{
var dep2 = Locator.Resolve<IDep2>();
dep2.DoSomething();
}
}
}
Approach 2 (Constructor injection)
public class MyType
{
private readonly IDep1 dep1;
private readonly IDep2 dep2;
public MyType(IDep1 dep1, IDep2 dep2)
{
this.dep1 = dep1;
this.dep2 = dep2;
}
public void MyMethod()
{
if (someRareCondition1)
{
dep1.DoSomething();
}
if (someRareCondition2)
{
dep2.DoSomething();
}
}
}
You can have many different voids that need different dependencies, but only in certain cases. Is it better to use a Service Locator for performance & memory?
Before I'll talk about the performance difference between the two approaches, I need to set the stage and talk about the Service Locator anti-pattern, because not every callback to the DI Container is an implementation of Service Locator.
Calls to the DI Container (or an abstraction over it) should be prevented from application code, e.g. inside your MVC controllers, or code part of your business layer. Callbacks from these parts of your code base can be considered examples of Service Locator.
Callbacks from parts of your application's startup path, a.k.a. the Composition Root, on the other hand, are not considered to be Service Locator implementations. That's because the Service Locator pattern is more than the mechanical description of a Resolve API, but rather a description of the role it plays in your application. These calls to the Container from inside the Composition Root are fine, beneficial, or even required for your application to function. Therefore, for the remaining part of my answer, I rather refer to "callback to the DI Container" rather than "using the Service Locator pattern."
When it comes to performance, there are many things to consider. It would be impossible for me to mention every possible performance bottleneck and tweak, but I'll mention the few things I think are most worthwhile to talk about in the context of your question.
Whether or not the lazy resolving of dependencies by calling back into the container is faster than constructor injection depends on a lot of factors. In general, I would say that in both cases performance is typically irrelevant as object composition would unlikely be your application's performance bottleneck. In most cases I/O takes up the bulk of the time. Time is typically better spent in optimizing I/O—it results in better performance gains with less investments.
That said, one thing to realize is that DI Containers are typically highly optimized and can do optimizations during compilation of the generated code that composes your application's object graphs. But these optimizations are thrown out when you start to break up object graphs by calling back into the container lazily. This makes constructor injection a more optimized approach, compared to breaking an object graph in pieces and resolving them one by one.
If I use Simple Injector—the DI Container that I maintain—as an example, it does quite aggressive optimizations on generated Expression trees before it starts compiling them. Those optimizations include:
Reducing size of compiled code by reusing compiled code within the graph.
Optimizing the request of scoped components within the graph, by caching them in variables (closures) inside the compiled method. This prevents duplicate dictionary look-ups.
Your mileage will obviously vary, but most DI Containers perform some kind of optimization. I'm unsure what kinds of optimizations the built-in ASP.NET Core DI Container applies though, but AFAIK its optimizations are limited.
There is overhead in calling your Container's Resolve method. At the very least it causes a dictionary lookup from the requested type to the code that is able compose the graph for that type, while dictionary look-ups tend not to happen (that much) for resolved dependencies. But in practice calls to Resolve tend to have some validity checks and other required logic that adds overhead to such call. This is another reason why constructor injection a more optimized approach, compared to doing callbacks.
Modern DI Containers are usually optimized so they can resolve big object graphs with ease (although with some containers there is a limit in the size of the object graph, although that limit is typically pretty big). Their overhead compared to creating those same object graphs manually (using plain old C#) is usually minimal (although differences and exceptions exist). But this only works if you follow the best practice to keep your injection constructors simple. When injection constructors are simple, it doesn't matter if you inject dependencies that are only used part of the time.
When you fail to follow this best practice, for instance by having injection constructors that callback to the database or perform some logging to disk, performance of object graph resolution can slow down considerably. This can be certainly painful when you're dealing with components that aren't always used. This seems to be the context of your question. Here's an example of a problematic injection constructor:
// This Injection Constructor does more than just receiving its dependencies.
public OrderShippingService(
ILogger logger, IConfigurationProvider provider)
{
// Storing the incoming dependency; this is fine.
this.logger = logger;
// Here it starts using its dependencies; this is problematic.
logger.LogInfo("Creating OrderShippingService.");
this.config = provider.Load<OrderShippingServiceConfig>();
logger.LogInfo("OrderShippingService Config loaded.");
}
My advise, therefore, is: follow the "simple injection constructors" best practice and make sure that injection constructors do no more than receive and store their incoming dependencies. Do not use dependencies from inside the constructor. This practice also helps when dealing with dependencies that are only used part of the time, because when those dependencies are fast to create, the problem goes away and using constructor injection will typically still be faster compared to doing callbacks.
On top of that, there are other best practices that should be followed, such as the Single-Responsibility Principle. Following it prevents constructors to get many dependencies and prevents the Constructor Over-Injection code smell. Object graphs that contain classes with many dependencies tend to become much bigger in size and, therefore, slower to resolve. This best practice doesn't help when dealing with those sometimes-used dependencies, though.
It might be the case, however, that you're unable to refactor such slow constructor, which requires you to prevent it to be eagerly loaded. But there are other cases in which eager loading can cause problems. That can happen, for instance, when your application uses Composites or Mediators. Composites and Mediators typically wrap many components and can forward an incoming call to a limited subset of them. Especially a Mediator, which typically forwards the call to a single component. For instance:
// Component using a mediator abstraction.
public class ShipmentController : Controller
{
private readonly IMediator mediator;
public void ShipOrder(ShipOrderCommand cmd) =>
mediator.Execute(cmd);
public void CancelOrder(CancelOrderCommand cmd) =>
mediator.Execute(cmd);
}
In the code above, the IMediator implementation should forward the Execute call to a component that knows how to handle the supplied command. In this example the ShipmentController forwards two different command types to the mediator.
Even with simple injection constructors, the previous example might cause performance problems when the application contains hundreds of those 'handlers' in case those handlers contain deep object graphs by themselves and are all recreated each time ShipmentController is composed.
The following implementation demonstrates these performance issues:
// I'm using C# 9 record type syntax here, because that makes the example succinct
record Mediator(IHandler[] Handlers) : IMediator
{
public void Execute<T>(T command) =>
Handlers.OfType<IHandler<T>>().Single().Execute(command);
}
}
In this example, all handlers are eagerly created before Mediator is, and injected into the Mediator's constructor, while a call to Execute just picks one from the list. This could lead to performance issues when there are many handlers that contain many dependencies of their own. This is because in order to execute one handler, all handlers with their dependencies need to be constructed. Not ideal.
To prevent this performance problem, calling back into the DI Container is an option to consider. It doesn't require the Service Locator anti-pattern, though, because the Mediator implementation (and, therefore, the callback) should reside inside your Composition Root. A possible IMediator implementation could look like this:
// As long as this implementation is placed inside the Composition Root,
// this is -not- an implementation of the Service Locator anti-pattern.
record Mediator(IServiceProvider Container) : IMediator
{
public void Execute<T>(T cmd) =>
Container.GetService<IHandler<T>>().Execute(cmd);
}
In this case, only the relevant handler is requested from the DI Container—not all of them. This means that the DI Container at this point, only creates the object graph for that particular handler.
In all cases, however, you should prevent calling back to the DI Container from within application code. I would even argue not to inject a Lazy<T> for a conditionally used dependency, even though some DI Containers have support for this. This only complicates the consumer's code, its tests, and makes it easy to forget to apply Lazy<T> to all constructors for that dependency.
Instead, creating a Proxy would be a better approach. That proxy would live inside the Composition Root and would either wrap a Lazy<T> or call back into the Container:
record DelayedDependencyProxy(IServiceProvider Container) : IDependency
{
private IDependency real;
public object SomeMethod()
{
if (real is null)
real = Container.GetService<RealDependency>();
return real.SomeMethod();
}
}
This Proxy keeps the consumers of IDependency clean and oblivious to the use of any mechanism to delay the creation of the dependency. Instead of injecting RealDependency into consumers of IDependency, you now inject DelayedDependencyProxy.
One last, but important note: do prevent premature optimizations. Prefer constructor injection over container callbacks even if container callbacks are faster. If you suspect any performance bottlenecks by constructor injection: measure, measure, measure. And do verify if the bottleneck really is in object composition itself, or in the constructor of one of your components. And if fixed, verify that this gives a performance boost significant enough to justify the increased complexity it causes. A performance win of 1 millisecond is not significant for most applications.
Related
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.
My application is built around "Services" like this:
public class ProfileService : BaseService {
private CommService _commService;
public ProfileService(CommService commService) {
_commService = commService;
}
public ApiResponseDto GetProfile(string profileUsername) {
using (var db = new appContext()){ db.DoStuff(); }
}
}
What I would like to do is push the db instantiation into BaseService, but I don't want to create a dbContext and incur the cost of such when I don't need it. So I'm thinking about doing something like this:
public class BaseService {
public AppContext _db;
public AppContext db(){
return _db ?? new AppContext();
}
}
And then all of my methods will access the db via db().DoStuff().
I don't like the idea of parentheses everywhere, but I like the idea of cleaning up my services footprints more.
My question is - if I create an instance of DbContext and don't use it, is there any cost? Or is the object just instantiated for future use? I hate to ask for opinions here as I know it's not allowed, but is this a step in the right direction of keeping things DRY?
Unit of Work Pattern
DbContext is effectively an implementation of the 'unit of work' pattern - once the DbContext is created, all changed done to the DbSet are then persisted in one go when you call SaveChanges.
So the further question you need to answer in order to properly answer your question is: What is the scope of the changes that make up your unit of work? In other words - what set of changes need to be made atomically - all succeed, or all fail?
A practical (if example of this - say you have an API endpoint that exposes an operation allowing the client to submit an order. The controller uses OrderService to submit the order, and then InventoryService to update the inventory associated with the items in the order. If each service has their own DbContext, you have a risk that the OrderService will succeed to persist the order submission, but the InventoryService will fail to persist the inventory update.
Dependency Injection
To combat this, a common pattern is to create a context per-request and let your IoC container create and dispose the context, and make it available to inject into services per request. This blog post gives a few options for DbContext management, and includes an example of configuring Ninject to do it.
What this means is your ctor will look like:
public ProfileService(CommService commService, AppContext context) {
_commService = commService;
_context = context;
}
And you can safely use the context there without having to worry about how it was created or where it came from.
Medhi's DbScopeFactory
However, my preferred approach for more complex applications is an excellent open source library documented up here: http://mehdi.me/ambient-dbcontext-in-ef6/. Injecting DbContext per request will work fine for simpler applications, but as your application gets more involved (e.g. multiple Contexts per application, multiple databases etc.), the finer grain control offered by his IDbContextScopeFactory is invaluable.
Edit to Add - Pros and Cons of Injection vs Construction
Following your comment asking for pros/cons of the approach you proposed, I'd say that generally, injection of dependencies (including DbContext) is a far more flexible and powerful approach, and can still achieve the goal of ensuring your devs don't have to be concerned with dbcontext lifecycle management.
The pros and cons are generally the same for all instances of dependency injection not just db context, but here are a few concrete issues with constructing the context within the service (even in a base service):
each service will have its own instance of the dbcontext - this can lead to consistency problems where your unit of work spans tasks carried out by multiple services (see example above)
It will be much more difficult to unit test your services, as they are constructing their own dependency. Injecting the dbcontext means you can mock it in your unit tests and test functionality without hitting the database
It introduces unmanaged state into your services - if you are using dependency injection, you want the IoC container to manage the lifecycle of services. When your service has no per-request dependencies, the IoC container will create a single instance of the service for the whole application, which means your dbcontext saved to the private member will be used for all requests/threads - this can be a big problem and should be avoided.
(Note: this is less of an issue if you are not using DI and constructing new instances of the services within controllers, but then you are losing the benefits of DI at the controller level as well...)
All services are now locked to using the same DbContext instance - what if, in the future you decide to split your database and some services need to access a different DbContext? Would you create two different BaseServices? Or pass in configuration data to allow the base service to switch? DI would take care of that, because you would just register the two different Context classes, and then the container would provide each service with the context it needs.
Are you returning IQueryables anywhere? If you are, then you run a risk that the IQueryable will cause the Db to hit even after the DbContext has gone out of scope - it may have been disposed by the garbage collector and will not be available.
From a dev perspective, I think nothing is simpler than the DI approach - simply specify the DbContext in your constructor, and let the DI container container take care of the rest.
If you are using DbContext per request, you don't even have to create or dispose the context, and you can be confident that IQueryables will be resolvable at any point in the request call stack.
If you use Mehdi's approach, you do have to create a DbContextScope, but that approach is more appropriate if you are going down a repository pattern path and want explicit control over the context scope.
As you can see, I'm far less concerned about the computational cost of constructing a DbContext when it's not needed (as far as I can tell, it's a fairly low cost until you actually use it to hit the db), and more concerned about the application architecture that permits unit testing and decoupling from dependencies.
In most arbitrary applications, there are many cross cutting concerns that need to be addressed among all available layers, e.g. logging, message bus, configuration. What I noticed is that in some classes, they tend to completely blow up the constructor if the modules are being injected using an IoC.
public class MyService : IService
{
public MyService(ILogger logger, IAppSettings settings, IEventBus eventBus...)
{
}
}
For usual cases of constructor over-injection, I tend to refractor the concerns into building blocks that belong closely together so I get fewer dependencies in a class. However, this is not possible with cross cutting concepts.
Among logging frameworks, static factories / services seem to very popular, e.g.
// Application root
MyLoggerService.SetFactory(log4NetFactory);
// Somewhere
MyLoggerService.GetLogger("name") // returns Log4NetLogger created by Log4NetFactory.
My question is: Is this approach a good one, for all kinds of cross cutting stuff? What are the drawbacks if the code may end up looking like this:
public class MyService : IService
{
private readonly IReallyNeedThat _dependency;
public MyService(IReallyNeedThat dependency)
{
_dependency = dependency;
}
private readonly ILogger _logger = LoggerService.GetLogger("MyService");
private readonly IEventBus _eventBus = EventBusService.GetEventBus();
private readonly IConfiguration _configuration = ConfigurationService.GetConfiguration(Level.Roaming)
private readonly IExceptionHandler _exceptionHandler = ExceptionPolicy.GetHandler();
private readonly ITracer _tracer = TraceManager.GetDebugTracer();
}
Moving the dependencies out of the constructor doesn't solve the problem, because you don't lower the amount of dependencies a class has and chances are big that you are still violating Single Responsibility principle and the Open/Close principle, causing your code to be hard to test, hard to change and hard to maintain.
Instead often a good solution is to pull those cross-cutting concerns out of your components and place them into components that are specially tailored for that cross-cutting concern and that component wrap the original component. In other words: create decorators.
This does probably force you to change the design of your classes, because when you don't have generic abstractions to define sets of related services, you will have to define a decorator per abstraction and that would cause a lot of code duplication, which is bad in almost all cases.
So instead, model your system around command/handlers and query/handlers and you'll be in a much better place. You can decorate each piece of business logic with a generic decorator that you define once and reuse all over the place. This keeps your system clean but still very flexible.
If you are more onto TDD, you can guess easily which approach is better.
With dependency injection, your code becomes more (unit)testable. You can inject dependencies via some mocking framework and create your unit tests without much headache.
But in case of static factories, since your factory classes are (hard)wired into your class, while unit testing there is no way out how you can inject them from outside your class.
Benefits of DI over static factories -
Concurrent Development - Think of a logging service that you are consuming, which is being built by somebody else and you are going to unit test your code (and you don't care unit testing of the logging service since you assume, it should be unit tested when you use it) . You batter use DI, inject the dependency using a mock object and done.
Speed - While unit testing your classes, definitely you wouldn't want them to take long time (so that it gives you a coffee break with every single change to your main class ;) ). You would definitely want you unit test to run in a blink of eye and report any error. Static factory that depends on external resources (e.g. network/DB, FileSystem) is going to take time. You better use DI, use a mock object and done.
Testability - DI helps isolating the client from their dependencies (promotes use of Interfaces), hence improves Testability (via use of mocks).
I am trying to get rid off static classes, static helper methods and singleton classes in my code base. Currently, they are pretty much spread over the whole code, especially so for the utility classes and the logging library. This is mainly due to the need for mocking ability as well as object-oriented design and development concerns, e.g. extensibility. I might also need to introduce some form of dependency injection in the future and would like to leave an open door for that.
Basically, the problem I have encountered is about the method of passing the commonly used references around. These are objects that are used by almost every class in the code base, such as the logging interface, the utility (helper) class interface and maybe an instance of a class that holds an internal common state for the assembly which most classes relate to.
There are two options, as far as I'm aware. One is to define a class (or an interface) that stores the common references, a context if you will, and pass the context to each object that is created. The other option is to pass each common reference to almost every class as a separate parameter which would increase the number of parameters of the class constructors.
Which one of these methods is better, what are the pros and cons of each, and is there a better method for this task?
I generally go with the context object approach, and pass the context object either to an object's constructor, or to a method -- depending on which one makes the most sense.
The context object pattern can take a few forms.
You can define an interface that has exactly the members you need, or you can generate a sort of container class. For example, when writing loosely-coupled components, I tend to have each component I implement have a matching interface, so that it can be reimplemented if desired. Then I register the objects on a "manager" object, something like this:
public interface IServiceManager
{
public T GetService<T>();
public T RequireService<T>();
public void RegisterService<T>(T service);
public void UnregisterService<T>(T service);
}
Behind the scenes there is a map from type to object, which allows me to extremely quickly assemble a large set of diverse components into a working whole. Each component asks for the others by interface, and the manager object is what glues them together. (If you correctly author your components, you can even swap out one service for another while the process is running!)
One would register a service something along these lines:
class FooService : IFooService { }
// During process start-up:
serviceManager.RegisterService<IFooService>(new FooService());
There is more overhead with this approach than with the flat-interface approach due to the dictionary lookup, but it has allowed me to build very sophisticated systems that can be easily redeployed with different service implementations. (And, as is usual, any bottlenecks I encounter are never in looking up a service object from a dictionary, but somewhere else such as the database.)
You're going to get varied opinions, but generally passing a separate parameter to the constructor for each dependency is preferred for a few reasons:
It clearly defines the actual dependencies for a class - with a "context" you don't know which parts of the context are used without digging into the code.
Generally having a lot of parameters to a constructor is a design smell, so using constructor injection helps you sniff out design flaws.
When testing you can mock out individual dependencies versus having to mock an entire context
I would suggest passing as a parameter to the constructor. This has great advantage for both dependency injection and unit testability ( mocking).
I've been using IoC (mostly Unity) and Dependency Injection in .NET for some time now and I really like the pattern as a way to encourage creation of software classes with loose coupling and which should be easier to isolate for testing.
The approach I generally try to stick to is "Nikola's Five Laws of IoC" - in particular not injecting the container itself and only using constructor injection so that you can clearly see all the dependencies of a class from its constructor signature. Nikola does have an account on here but I'm not sure if he is still active.
Anyway, when I end up either violating one of the other laws or generally ending up with something that doesn't feel or look right, I have to question whether I'm missing something, could do it better, or simply shouldn't be using IoC for certain cases. With that in mind here are a few examples of this and I'd be grateful for any pointers or further discussion on these:
Classes with too many dependencies. ("Any class having more then 3 dependencies should be questioned for SRP violation"). I know this one comes up a lot in dependency injection questions but after reading these I still don't have any Eureka moment that solves my problems:
a) In a large application I invariably find I need 3 dependencies just to access infrastructure (examples - logging, configuration, persistence) before I get to the specific dependencies needed for the class to get its (hopefully single responsibility) job done. I'm aware of the approach that would refactor and wrap such groups of dependencies into a single one, but I often find this becomes simply a facade for several other services rather than having any true responsibility of its own. Can certain infrastructure dependencies be ignored in the context of this rule, provided the class is deemed to still have a single responsibility?
b) Refactoring can add to this problem. Consider the fairly common task of breaking apart a class that has become a bit big - you move one area of functionality into a new class and the first class becomes dependent on it. Assuming the first class still needs all the dependencies it had before, it now has one extra dependency. In this case I probably don't mind that this dependency is more tightly coupled, but its still neater to have the container provide it (as oppose to using new ...()), which it can do even without the new dependency having its own interface.
c) In a one specific example I have a class responsible for running various different functions through the system every few minutes. As all the functions rightly belong in different areas, this class ends up with many dependencies just to be able to execute each function. I'm guessing in this case other approaches, possibly involving events, should be considered but so far I haven't tried to do it because I want to co-ordinate the order the tasks are run and in some cases apply logic involving outcomes along the way.
Once I'm using IoC within an application it seems like almost every class I create that is used by another class ends up being registered in and/or injected by the container. Is this the expected outcome or should some classes have nothing to do with IoC? The alternative of just having something new'd up within the code just looks like a code smell since its then tightly coupled. This is kind of related to 1b above too.
I have all my container initialisation done at application startup, registering types for each interface in the system. Some are deliberately single instance lifecycles where others can be new instance each time they are resolved. However, since the latter are dependencies of the former, in practice they become a single instance too since they are only resolved once - at construction time of the single instance. In many cases this doesn't matter, but in some cases I really want a different instance each time I do an operation, so rather than be able to make use of the built in container functionality, I'm forced to either i) have a factory dependency instead so I can force this behaviour or ii) pass in the container so I can resolve each time. Both of these approaches are frowned upon in Nikola's guidance but I see i) as the lesser of two evils and I do use it in some cases.
In a large application I invariably find I need 3 dependencies just to access infrastructure (examples - logging, configuration, persistence)
imho infrastructure is not dependencies. I have no problem using a servicelocator for getting a logger (private ILogger _logger = LogManager.GetLogger()).
However, persistence is not infrastructure in my point of view. It's a dependency. Break your class into smaller parts.
Refactoring can add to this problem.
Of course. You will get more dependencies until you have successfully refactored all classes. Just hang in there and continue refactoring.
Do create interfaces in a separate project (Separated interface pattern) instead of adding dependencies to classes.
In a one specific example I have a class responsible for running various different functions through the system every few minutes. As all the functions rightly belong in different areas, this class ends up with many dependencies just to be able to execute each function.
Then you are taking the wrong approach. The task runner should not have a dependency on all tasks that should run, it should be the other way around. All tasks should register in the runner.
Once I'm using IoC within an application it seems like almost every class I create that is used by another class ends up being registered in and/or injected by the container.*
I register everything but business objects, DTOs etc in my container.
I have all my container initialisation done at application startup, registering types for each interface in the system. Some are deliberately single instance lifecycles where others can be new instance each time they are resolved. However, since the latter are dependencies of the former, in practice they become a single instance too since they are only resolved once - at construction time of the single instance.
Don't mix lifetimes if you can avoid it. Or don't take in short lived dependencies. In this case you could use a simple messaging solution to update the single instances.
You might want to read my guidelines.
Let me answer question 3. Having a singletons depend on a transient is a problem that container profilers try to detect and warn about. Services should only depend on other services that have a lifetime that is greater than or equals to that of their own. Injecting a factory interface or delegate to solve this is in general a good solution, and passing in the container itself is a bad solution, since you end up with the Service Locator anti-pattern.
Instead of injecting a factory, you can solve this by implementing a proxy. Here's an example:
public interface ITransientDependency
{
void SomeAction();
}
public class Implementation : ITransientDependency
{
public SomeAction() { ... }
}
Using this definition, you can define a proxy class in the Composition Root based on the ITransientDependency:
public class TransientDependencyProxy<T> : ITransientDependency
where T : ITransientDependency
{
private readonly UnityContainer container;
public TransientDependencyProxy(UnityContainer container)
{
this.container = container;
}
public SomeAction()
{
this.container.Resolve<T>().SomeAction();
}
}
Now you can register this TransientDependencyProxy<T> as singleton:
container.RegisterType<ITransientDependency,
TransientDependencyProxy<Implementation>>(
new ContainerControlledLifetimeManager());
While it is registered as singleton, it will still act as a transient, since it will forward its calls to a transient implementation.
This way you can completely hide that the ITransientDependency needs to be a transient from the rest of the application.
If you need this behavior for many different service types, it will get cumbersome to define proxies for each and everyone of them. In that case you could try Unity's interception functionality. You can define a single interceptor that allows you to do this for a wide range of service types.