Dependency Injection in C#

netcore

Today we will be going to read how dependency injection works in c#. This way we can achieve loosely coupled code following the D in SOLID principles. It’s like delegating your work to some other (eg: the flow of code) while you focus on your main task.

This helps you to create a single unit of work. As it doesn’t depend on other libs or DLLs. It makes your code more testable (Test-driven design (TDD)). So let’s start with what is dependency injection in c#?


What is dependency injection in C#?

Focus on the work, do not create unnecessary references

Dependency Injection in C# uses the IoC principle. IoC stands for Inversion of Control, this is used to invert different kinds of controls like a class, etc. This include

  • Control over the flow of an application
  • Control over object creation
  • Dependent object creation and binding

Just take a real-world example of managing a restaurant order deliveries.

Suppose you run a restaurant and your forte is to maintain the hygiene, provide grade A services and give quality food to your customer. To increase your business you have started taking orders on phone via the app as well. Since having delivery boys to deliver and manage the order is one hell of a tedious task you take the help of Zomato or Doordash to manage it so you can focus on your main work and that is to make quality food.

You need to keep one thing in mind, the “new” keyword is the enemy. Do not use it in your main class. There are three main components/Classes to achieve the Dependency Injection in c#.

  1. Client Class: The client class (dependent class) is a class that depends on the service class
  2. Service Class: The service class (dependency) is a class that provides service to the client class.
  3. Injector Class: The injector class injects the service class object into the client class.

Let us start with the basic way of creating an Inversion of Control class in C#

Inversion of Control

Let us achieve your first IoC object – Factory Class to Retrieve Object – C#

Suppose you have a data access layer and your business layer. How will you add a reference of DB layer to the business layer? Create a factory method to invoke a new instance of DB layer like below. This will create an inversion of control by making your creation of object via a different class. Like Doordash’s example above.

Here is the business Layer class, you can see how the dbcontext is created to access the connection.

public class BusinessLayer
{
    public BusinessLayer() {
    }
    public string GetCustomerName(int id) {
        DBLayer _dbContext =  Factory.GetConnection();
        return _dbContext.GetDetailsByID(id);
    }
}

Lets write the DB Layer

public class DBLayer
{
    public DBLayer() {
    }
    public string GetDetailsByID(int id) {
        return "John Doe"; //To do connect to DBs
    }
}

Let’s write the Factory class which is based on the Factory pattern

public class Factory
{
    public static DBLayer GetConnection() 
    {
        return new DBLayer();
    }
}

Kudos guys, you have achieved your first Inversion of Control.

Dependency Inversion Principle

High Level, Low Level, Abstraction, Loose coupling… What??

By Definition:

  1. High-level modules should not depend on low-level modules. Both should depend on the abstraction.
  2. Abstractions should not depend on details. Details should depend on abstractions.

High-Level Module & Low-Level Module

A high-level module is a module that depends on other modules, like the business layer depends on the DB layer, so here BusinessLayer is a high-level module.

As per definition, the business layer should not depend on DB layer, which is a low-level concrete class, rather they both should depend on abstractions.

Abstraction

Abstraction is one of the pillars of OOPs, which literally means non-concrete. These are like contracts that when inherited into a concrete class need to be implemented. You can achieve abstraction using Interfaces and Abstract class. Both of which you can’t create instances of.

Loose Coupling

So as mentioned in the above example. BusinessLayer depends directly on DBLayer, we need to make necessary changes to make both of them depend on abstractions or interfaces.

Dependency Inversion Implementation – Code

So let’s rewrite the above code. First let us create an interface, for loose coupling.

public interface IEntity
{
    string GetDetailsByID(int id);
}

and the Factory and DB layer class too

public class Factory
{
    public static IEntity GetConnection() {
        return new DBLayer();
    }
}


public class DBLayer:IEntity {
    public DBLayer() {
    }
    public string GetDetailsByID(int id) {
        return "John Doe"; 
        //To do connect to DBs
    }
}

Let’s rewrite our Business Layer as well:

public class BusinessLayer
{
    IEntity _dbContext ;
    public BusinessLayer() {
        _dbContext = Factory.GetConnection();
    }
    public string GetCustomerName(int id) {      
        return _dbContext.GetDetailsByID(id);
    }
}

Now after this you might be clear with the following concepts:

  • What is dependency injection in C#?
  • Inversion of Control – C#
  • Dependency Inversion Principle – C#

Since we have not still completed the complete Loose Coupling, as you can see we are still using the new keyword in the Factory class. Let us start with the final topic here, which will complete you as a very good programmer.

Dependency Injection

The final nail in the coffin.

As we read above, we have three types of classes in dependency injection namely: Client Class, Service Class, and Injector Class:

So the injector class creates an object of the service class and injects that object into a client object.

There are three types of Dependency Injection:

Constructor Injection: In the constructor injection, the injector supplies the service (dependency) through the client class constructor.

Property Injection: In the property injection (aka the Setter Injection), the injector supplies the dependency through a public property of the client class.

Method Injection: In this type of injection, the client class implements an interface that declares the method(s) to supply the dependency and the injector uses this interface to supply the dependency to the client class.

In this article, we will only go through constructor injection, and let us keep the other two for a different article.

Note: In the business layer:

  • Remove the factory class first
  • Make a new service layer
  • This new service layer will create an object to be passed or injected into the client(Business Layer).
public class BusinessLayer
{
    IEntity _dbContext;
    public BusinessLayer(IEntity dbContext) {
        _dbContext = dbContext;
    }
    public string GetCustomerName(int id) {      
        return _dbContext.GetDetailsByID(id);
    }
}

public interface IEntity
{
    string GetDetailsByID(int id);
}

public class DBLayer:IEntity
{
    public DBLayer() {
    }
    public string GetDetailsByID(int id) {
        return "John Doe"; 
        //To do connect to DBs
    }
}

Let us write a service class that will call the above methods:

public class ServiceLayer
{
    BusinessLayer _BL;
    public ServiceLayer() {
        _BL = new BusinessLayer(new DBLayer());
    }
    public string GetCustomerName(int id) {
        //Writing same name in service and business layer reduces confusion
        return _BL.GetCustomerName(id);
    }
}

In the above examples, you are using a new keyword only in the service layer which is injecting dependencies of the DB layer into the business layer. And your business layer is independent of tight coupling.

Happy coding guys, you are one hell of a programmer now, feel free to comment.

Next Post in continuation:

Different ways to achieve Dependency Injection

That’s all folks. Feel free to visit my other content as well.

4 thoughts on “Dependency Injection in C#”

  1. Pingback: Thought Gem - Different ways to achieve Dependency Injection

  2. Pingback: Class structure playing card problem in c# - Thought Gem

  3. Pingback: Delegates in C# - Thought Gem

  4. Pingback: SQL Server - Clustered and Non-Clustered - Thought Gem

Leave a Comment

Your email address will not be published. Required fields are marked *