Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why we need framework to do the Dependency Resolver?

I always saw people always talking about using framework like Ninject, Unity, Windsor to do the dependency resolver and injection. Take following code for example:

public class ProductsController : ApiController
{
    private IProductRepository _repository;

    public ProductsController(IProductRepository repository)  
    {
        _repository = repository;
    }
} 

My question is: why can't we simply write as:

public class ProductsController : ApiController
{
    private IProductRepository _repository;

    public ProductsController() :this(null)
    {}

    public ProductsController(IProductRepository repository)  
    {
        _repository = repository?? new ProductRepository();
    }
} 

In that case seems we don't need any framework, even for the unit test we can easily mock.

So what's the real purpose for those framework?

Thanks in advance!

like image 602
Samuel Avatar asked Sep 03 '14 07:09

Samuel


People also ask

Why do we need a dependency injection framework?

We should use the dependency framework because of the following: It helps us in managing the complex dependencies easily. It makes the unit testing easy by enabling us to pass all the dependencies from outside so that we can easily use the mocked objects. It easily manages the scope(lifecycle) of the object.

Which framework is used for dependency injection?

. NET supports the dependency injection (DI) software design pattern, which is a technique for achieving Inversion of Control (IoC) between classes and their dependencies. Dependency injection in . NET is a built-in part of the framework, along with configuration, logging, and the options pattern.

What is dependency in framework?

In software engineering, dependency injection is a design pattern in which an object or function receives other objects or functions that it depends on.

What does a dependency resolver () do?

A dependency resolver is just a service locator integrated with the ASP.NET MVC codebase. Resolvers are a way to add the implementation of the Dependency Inversion principle into an existing (large) codebase.


2 Answers

In that case your ProductsController still depends on a low level component (the concrete ProductRepository in your case) which is a violation of the Dependency Inversion Principle. Whether or not this is a problem depends on multiple factors, but it causes the following problems:

  • The creation of the ProductRepository is still duplicated throughout the application causing you to make sweeping changes throughout the application when the constructor of ProductRepository chances (assuming that ProductRepository is used in more places, which is quite reasonable) which would be an Open/Closed Principle violation.
  • It causes you to make sweeping changes whenever you decide to wrap this ProductService with a decorator or interceptor that adds cross-cutting concerns (such as logging, audit trailing, security filtering, etc) that you surely don't want to repeat that code throughout all your repositories (again an OCP violation).
  • It forces the ProductsController to know about the ProductsRepository, which might be a problem depending on the size and complexity of the application your are writing.

So this is not about the use of frameworks, it's about applying software design principles. If you decide to adhere to these principles to make your application more maintainable, the frameworks like Ninject, Autofac and Simple Injector can help you with making the startup path of your application more maintainable. But nothing is preventing you from applying these principles without the use of any tool or library.

like image 109
Steven Avatar answered Nov 08 '22 12:11

Steven


Small disclaimer: I'm an avid Unity user, and here are my 2 cents.

1st: Violation of SOLID (SRP/OCP/DIP)

Already stated by @democodemonkey and @thumbmunkeys, you couple the 2 classes tightly. Let's say that some classes (let it be ProductsThingamajigOne and ProductsThingamajigTwo) are using the ProductsController, and are using its default constructor. What if in the architect decides that the system should not use a ProductsRepository that saves Products into files, but should use a database or a cloud storage. What would the impact be on the classes?

2nd: What if the ProductRepository needs another dependency?

If the repository is based on a database, you might need to provide it with a ConnectionString. If it's based on files, you might need to provide it with a class of settings providing the exact path of where to save the files - and the truth is, that in general, applications tend to contain dependency trees (A dependent on B and C, B dependent on D, C dependent on E, D dependent on F and G and so on) that have more then 2 levels, so the SOLID violations hurts more, as more code has to be changed to perform some task - but even before that, can you imagine the code that would create the whole app? Fact is, classes can have many dependencies of theirs own - and in this case, the issues described earlier multiply.

That's usually the job of the Bootstrapper - it defines the dependency structure, and performs (usually) a single resolve that brings the whole system up, like a puppet on a string.

3rd: What if the Dependency-Tree is not a tree, but a Graph?

Consider the following case: Class A dependent on classes B and C, B and C both are dependent on class D, and are expecting to use the same instance of D. A common practice was to make D a singleton, but that could cause a lot of issues. The other option is to pass an instance of D into the constructor of A, and have it create B and C, or pass instances of B and C to A and create them outside - and the complexity goes on and on.

4th: Packing (Assemblies)

Your code assumes that 'ProductsController' can see 'ProductRepository' (assembly-wise). What if there's no reference between them? the Assembly Map can be non-trivial. usually, the bootstrapping code (I'm assuming that it's in code and not in configuration file for a second here) is written in an assembly that references the entire solution. (This was also described by @Steven).

5th: Cool stuff you can do with IoC containers

Singletons are made easy (with unity: simply use a 'containercontrolledlifetimemanager' when registering), Lazy Instantiation made really easy (with unity: register mapping of and ask in the constructor for a Func). Those are just a couple of examples of things that IoC containers give you for (almost) free.

like image 43
Felix Avatar answered Nov 08 '22 12:11

Felix