Why do we need infrastructure to solve dependencies?

I always saw that people always talked about using a framework like Ninject, Unity, Windsor to make a dependency and injection converter. Take the following code, for example:

public class ProductsController : ApiController { private IProductRepository _repository; public ProductsController(IProductRepository repository) { _repository = repository; } } 

My question is: why can't we just write:

 public class ProductsController : ApiController { private IProductRepository _repository; public ProductsController() :this(null) {} public ProductsController(IProductRepository repository) { _repository = repository?? new ProductRepository(); } } 

In this case, we don’t need any structure, even for unit test we can easily make fun of it.

So what is the real purpose for these frameworks?

Thanks in advance!

+8
c # dependency-injection dependencies
source share
8 answers

In this case, your ProductsController still depends on the low-level component (the specific ProductRepository in your case), which is a violation of the Dependency Inversion Principle . Regardless of whether this is a problem, it depends on several factors, but it causes the following problems:

  • Creating a ProductRepository is still duplicated throughout the application, which leads to widespread changes throughout the application when there is the likelihood of a ProductRepository constructor (assuming that ProductRepository used in more places, which is quite reasonable) which will violate the open / closed principle .
  • This forces you to make drastic changes whenever you decide to wrap this ProductService decorator or interceptor that adds cross-cutting issues (such as logging, audit completion, security filtering, etc.) that you certainly don't want to repeat this code in all your repositories (again, an OCP violation).
  • It makes the ProductsController know about the ProductsRepository , which can be a problem depending on the size and complexity of the application you are writing.

Thus, this is not about using frameworks, but about applying the principles of software development. If you choose to adhere to these principles to make your application easier to use, environments such as Ninject, Autofac, and Simple Injector can help you simplify the process of launching your application. But nothing prevents you from applying these principles without using any tool or library.

+3
source share

A small disclaimer: I am an avid Unity user, and here are my 2 cents.

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

Already declared by @democodemonkey and @thumbmunkeys, you are closely linking 2 classes. Suppose some classes (let it be ProductsThingamajigOne and ProductsThingamajigTwo) use the ProductsController and use its default constructor. What to do if the architecture decided that the system should not use the ProductsRepository, which stores the Products in files, but should use a database or cloud storage. What impact will this have on classes?

2nd: what if ProductRepository needs another dependency?

If the repository is database-based, you may need to provide it with a ConnectionString. If it is file-based, you may need to provide it with a parameter class that provides the exact path to where the files are saved - and the truth is that, in the general case, applications usually contain dependency trees (A depends on B and C)., B depends on D, C depends on E, D depends on F and G, etc.), which have more than 2 levels, so SOLID violations do more harm, because to complete a task you need to change more code - but even before that, can you imagine the code that will create the whole application? In fact, classes can have many of their own dependencies, in which case the problems described earlier multiply.

This is usually the work of Bootstrapper - it defines the structure of dependencies and performs (usually) one resolution, which puts the whole system in action, like a puppet in a string.

3rd: What if the dependency tree is not a tree, but a graph?

Consider the following case: a class A, depending on classes B and C, B and C, both depends on class D, and expect to use the same instance of D. It was common practice to make D single, but this could raise a lot of questions. Another option is to pass instance D to constructor A and force it to create B and C, or pass instances of B and C to and create them from the outside - and the complexity goes on and on.

4th: packaging (assembly)

Your code assumes that the "ProductsController" can see the "ProductRepository" (assembly). What if there are no links between them? An assembly map can be nontrivial. As a rule, the boot code (I assume that it is in the code, and not in the configuration file for a second) is written in the assembly, which refers to the whole solution. (This has also been described by @Steven).

5th: cool things you can do with IoC containers

Singletones are made easy (using unity: just use the "containercontrolledlifetimemanager" when registering), Lazy Instantiation is really easy (with unity: register a mapping and ask in the Func constructor). These are just a couple of examples of what IoC containers give you (almost) for free.

+3
source share

Of course, you can do this, but it can cause the following problems:

  • IProductRepository dependency is no longer explicit; it looks like an optional dependency
  • Other parts of the code may create a different implementation of IProductRepository , which is likely to be a problem in this case.
  • The class becomes closely related to the ProductsController as it internally creates a dependency.

In my opinion, this is not a question of structure. The point is to make the modules composite by exposing their dependencies in the constructor or property. Your example confuses this somewhat.

+2
source share

If the ProductRepository class ProductRepository not defined in the same assembly as the ProductsController (or if you ever want to transfer it to another assembly), you just presented a dependency that you do not want.

This is an anti-pattern described as "Bastard Injection" in Mark Siman's original book Dependency Injection in .Net.

However, if the ProductRepository will ALWAYS be in the same assembly as the ProductsController , and if it does not depend on what the rest of the ProductsController assembly depends on, it could be local default - in this case it will be normal.

From the class names, I am sure that such a dependency MUST NOT be introduced, and you are looking at the bastard injection.

+1
source share

Here, the ProductsController is responsible for creating the ProductRepository .

What happens if ProductRepository requires an additional parameter in its constructor? Then the ProductsController will have to change, and this violates the SRP.

As well as complexity for all of your objects.

Also, how unclear is the need for the caller to pass in the child, or not?

0
source share

The main goal is to separate the creation of an object from its use or consumption. The creation of the "usually" object is carried out according to factory classes. In your case, factory classes will be created to return an object of the type that implements the IProductRepository interface.

In some frameworks, as in Sprint.Net, factory classes create objects declaratively written in the configuration (for example, in app.config or web.config). Thus, the program is completely independent of the object that it must create. It can be pretty strong at times.

0
source share

It is important to distinguish between dependency injection and control inversion are not the same thing. You can use dependency injection without IOC structures such as unity, ninject ... doing manual injection, which they often call poor DI.

In my blog I recently wrote a post about this problem http://xurxodeveloper.blogspot.com.es/2014/09/Inyeccion-de-Dependencias-DI.html

Returning to your example, I see implementation flaws.

1 - Products The controller is dependent on nodule, not abstraction, SOLID violation

2 - If the interface and the repository live in different projects, you will have to refer to the project in which the repository is located

3. If in the future you need to add a parameter to the constructor, you will have to change the controller when it is just a client of the repository.

4- The controller and repository can be developed for different programmers, the programmer-programmer must know how to create a repository

0
source share

consider this question:

suppose in the future if you want to add a CustomProductRepository instead of a ProductRepository in the ProductsController to software that is already deployed to a client site.

with Spring.Net, you can simply update the spring configuration file (xml) to use CustomProductRepository . This way you can avoid re-compiling and reinstalling the software on the client site since you have not changed the code.

0
source share

All Articles