Dependency Injection and Inversion of Control on .Net Core

Alex Alves
8 min readApr 26, 2020

Do you know about the terms Dependency Inject and/or Inversion of Control? No? Let’s go to talk about it! I’ll explain to you how and why do you need to use these patterns. And finally, we’ll develop a .Net Core simple application that uses these concepts.

Firstly, what do you think to learn the theory? Let’s start learning a little bit about Dependency Injection!

Dependency Injection

Dependency Injection, also known as DI, is a Design Pattern used to avoid coupling inside your code. According to the best practices in software development and part of one of S.O.L.I.D. principles, a class should depend on abstractions and not from concrete classes.

A dependency is an object that your class needs to do the work, in other words, this object isn’t created inside your class. The dependency is injected into a class that uses it, so the dependency is required to be external. The object instantiation (that is the dependency) must not be inside the class, but outside it. Look below a simple example:

In this case, when I instantiate the LeaderboardServiceManager class, I need to pass an IMapper type instantiate. Look, the constructor receives a parameter (mapper) and its value is set to a variable (_mapper) which will be used in the other functions of this class.

Benefits of using it:

  • Low coupling
  • Simplicity
  • Ease of maintenance
  • Ease to learn about the code/project
  • Ease to test your code

Exists three most common types of Dependency Injection:

1) Constructor

It is the most common type of DI. When the class’ constructor receives a class or an abstraction of another class as a parameter it is a DI. Look at another example below:

In this case, I receive an ISmtpClient type instantiate by the constructor to use it in some function of my class.

2) Getter and Setter

Injection by properties (get and set). It occurs when exists a class or an abstraction exposed as property. Look the example below:

We have a property SmtpClient of ISmtpClient type, so to this property must be attributed a valid value.

3) Interface Implementation

When the class has a method who receives an abstraction by parameter. In the following example, the method setSmtpClient receives the smtpClient variable of the ISmtpClient interface type (an abstract type).

4) Service locator

It is often called a container. It happens when you have a container that provides many instances and you can just request a specific instance to it. Like this:

First, we should have a class to register and provides the instances
Second, in another part of your code, we can register all the instances
And finally, we can use it like this

And next, let’s go to talk about the Inversion of Control!

Inversion of Control

Inversion of Control, or IoC which is best known, is a Design Pattern. It is a different way of manipulating the objects’ control. It usually depends on the Dependency Injection, because the instantiation of an object becomes a responsibility of the architecture, not of the developer.

And now, we arrived where we really want to: IoC attends one of the S.O.L.I.D. principles, the Dependency Inversion, and that explains how it is so important. Let’s review it.

S.O.L.I.D. is an acronym for five important design principles when you work with OOP (Object Oriented Programming), and each letter means:

  • S: Single responsibility
  • O: Open closed
  • L: Liskov substitution
  • I: Interface segregation
  • D: Dependency inversion

Now, I think we have all of the knowledge to do something more practical. Let’s go?

Development

We’re going to build a simple WebApi application, using the Visual Studio 2019 and the Asp.Net Core 3.1. This application will calculate the percentage of achievement of a club that plays into a racing points championship. So, this API will receive the club’s name, the number of points earned and the number of games played.

Creating the project

Open your Visual Studio and select the ‘ASP.NET Core Web Application’ option, like below:

Next, name your project, select a folder (or accept the default option), name your solution (or accept the default option) and click on the ‘Create’ button:

Now, choose the ‘API’ option, like below and click on Create button:

Dividing our project into layers

Pay attention here, as this is a project example I’ll divide it into folders without a strong criteria, but it would be more correct to divide it into projects to isolate different contexts.

Let’s make three other folders, called Domain, Services, and Dependencies:

  • Controllers: Layer that contains classes responsible for responding for request API
  • Dependencies: Layer responsible to do the Inversion of Control of project
  • Domain: Layer containing the model classes of the project
  • Services: Layer that contains the logic rules

Into the Domain folder, let’s make more two sub-folder, called Entities and Interfaces. And into a sub-folder Entities, make another sub-folder called DTOs (Data Transfer Objects):

  • Entities: Has the anemic classes
  • Entities.DTOs: Has classes to receive data in controllers
  • Interfaces: Contract classes

Building our domain layer

First let’s create the Club entity, into the Entities folder. Into this entity will have two properties, called Name and Percentage.

Club.cs is the model that we will return.

Second, let’s create a ClubDTO class, into the DTOs sub-folder. Into this entity will have three properties, called Name, PointsEarned, and GamesPlayed.

ClubDTO.cs is the model that we will receive in the controller.

And finally, let’s create the IServiceClube interface. It has a contract reference to calculate the percentage of achievement, like below:

Building our service layer

In this layer, we need only one class, called ServiceClub. We’ll create it into the Services folder and it will inherit from the IServiceClub interface.

When we put the inheritance in this class, we need to implement the contracts, like below:

Now, let’s implement the logic:

Building our dependency layer

Into the Dependencies folder create a static class called ServicesDependency.

Now, we go to use a resource called Extension Methods. This resource allows us to “add” methods to existing types without creating a new derived type. In this case, we extended the IServiceCollection type. This type provides an intern container service called IServiceProvider which allows us to register our dependencies. So, we can create a static method into the dependency class, like this:

.NET Core provides three kinds of dependency injection, based in your lifetimes:

  • Transient: services that will be created each time they are requested
  • Scoped: services that will be created once per client request (connection)
  • Singleton: services that will be created only at the first time they are requested

And now, we add our dependencies. In this project, we have only one dependency that reference to our Service/Logic, and we’ll use the Transient Lifetime:

Building our controller layer

First, we need to create a controller class, called ClubController, into the Controllers folder. We can create it by “scaffold”, so it’ll create all the structure that we need.

What do you think about using what we learned about Dependency Injection? Let’s use the dependency injection by constructor to use the services we created before, like below:

And finally, let’s create our Action Method (I will not explain in more detail because this is another subject). Attention for the red highlight, it is when we use the dependency injection attribute:

Final adjustments

Lastly, we need to register our Extension Method created for dependencies registers. The place we do it is in the Startup class, inside of ConfigureServices method:

And now, our application can run without any problem!

The execute

First, run your project (press F5). When the browser opens, type this URL:

https://localhost:44343/api/club/CalculatePercentage?name=Test%20Club&pointsEarned=10&gamesPlayed=4

Attention for your application port, in my case, it is 44343.

Let’s see the data that we receive:

And note that the ServiceClub was instantiated without our interference/command.

And the result:

Conclusion

We observed that the instantiation of the services that were injected is a responsibility of the architecture/project, not of me and you, the developers. And also that it reduces the coupling and facilitates testing, maintenance, and, most important, reusing the code.

The code you can find here.

--

--

Alex Alves

Bachelor in Computer Science, MBA in Software Architecture and .NET Developer.