👉🏼 Click here to Join I ❤️ .NET WhatsApp Channel to get 🔔 notified about new articles and other updates.
Introducing Dependency Injection in .NET

Introducing Dependency Injection in .NET

Author - Abdul Rahman (Bhai)

Dependency Injection

7 Articles

Improve

Table of Contents

  1. What we gonna do?
  2. Why we gonna do?
  3. How we gonna do?
  4. Summary

What we gonna do?

In this article, let's learn about Dependency Injection in .NET.

.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.

Why we gonna do?

A dependency is an object that another object depends on. Examine the following ClassB class with that other classes depend on:


public class ClassB 
{
  // omitted for brevity
} 
            

A class can create an instance of the ClassB class to make use of it. In the following example, the ClassB class is a dependency of the ClassA class:


public class ClassA
{
    private readonly ClassB _classB = new();

    public void Run()
    {
        // omitted for brevity
    }
}
            

The class creates and directly depends on the ClassB class. Hard-coded dependencies, such as in the previous example, are problematic and should be avoided for the following reasons:

  • To replace ClassB with a different implementation, the ClassA class must be modified.
  • If ClassB has dependencies, they must also be configured by the ClassA class. In a large project with multiple classes depending on ClassB, the configuration code becomes scattered across the app.
  • This implementation is difficult to unit test. The app should use a mock or stub ClassB class, which isn't possible with this approach.

So let's try to get the instance of ClassB from constructor of ClassA.


public class ClassA
{
    private readonly ClassB _classB;

    ClassA(ClassB classB)
    {
        _classB = classB;
    }
    
    public void Run()
    {
        // omitted for brevity
    }
}
            

Here is the complete wire up in Program.cs.


class Program
{
    var classB = new ClassB();
    var classA = new ClassA(classB);
    
    classA.Run();
}
            

Dependency injection addresses these problems through:

  • The use of an interface or base class to abstract the dependency implementation.
  • Registration of the dependency in a service container. .NET provides a built-in service container, IServiceProvider. Services are typically registered at the app's start-up and appended to an IServiceCollection. Once all services are added, you use BuildServiceProvider to create the service container.
  • Injection of the service into the constructor of the class where it's used. The framework takes on the responsibility of creating an instance of the dependency and disposing of it when it's no longer needed.

class Program
{
    using var host = Host.CreateDefaultBuilder(args)
                         .ConfigureServices((context, services) => 
                         { 
                             services.AddTransient<ClassB>();
                             services.AddTransient<ClassA>();
                         })
                         .Build();

    var classA = host.Services.GetRequiredService<ClassA>();
    classA.Run();
}
            

How we gonna do?

Dependency Injection visualization

DI enables decoupling and supports development of loosely-coupled code. DI supports implementation of two related concepts, inversion of control and the dependency inversion principle.

Inversion of Control
- A framework controls which code is executed next, not your code.
Dependency Inversion Principle
- High-level modules should not depend on low-level modules. Both should depend on abstractions.
dependency-injection-in-dotnet

Working with Dependency Injection

DI Configuration consist of two main phases, Registration phase and Resolving Phase.

Steps

  1. Install Microsoft.Extensions.Hosting Nuget Package.
  2. Register services using

    
    var host = Host.CreateDefaultBuilder(args)
                   .ConfigureServices((context, services) => 
                   { 
                      //Registration goes here 
                   })
                   .Build();
                        
  3. Resolve services using Host.Services.GetRequiredService<YourService>();
working-with-dependency-injection-in-dotnet

Phases of Dependency Injection

Registration Phase

Register types in container so it knows of their existence and when to construct them.

  1. Register types for later use.
  2. Indirection through service type and implementing type.
  3. Choose a lifetime.

Registering Types

When registering types you specify the lifetime, the requested service type and the implementing type. If these types are the same you provide it once.


services.AddTransient<IService, MyService>();
services.AddSingleton<ClassA>();
            

Resolving Phase

Container is responsible for instantiating types and providing them when requested.

  1. Resolves and creates types directly.
  2. Provides dependencies of types you work with.
  3. Provides dependencies to dependencies of the types you work with.
  4. Manage the lifetimes of the types.

Resolving Types

When resolving a type, you request an instance of service type. The container will find the implementing type, instantiate it if needed, and return it to you.

If the implementing type has dependencies, they are provided to the implementing type as well.


host.Services.GetRequiredService<IService>();
host.Services.GetRequiredService<ClassA>();
            
phases-of-dependency-injection-in-dotnet

Advantages

  1. No longer calling constructors.
  2. Container calls the constructors.
  3. Not concerned with ordering registrations.
  4. Not concerned with dependencies of each type.

Summary

In this article, we learn't what is Dependency Injection in .NET. We understood how classes are invoked in traditional flow using new() keyword and how dependency injection helped us to avoid the new() glue and makes it easy to manage dependencies. In next article lets talk about lifetimes in dependency injection in .NET.

👉🏼 Click here to Join I ❤️ .NET WhatsApp Channel to get 🔔 notified about new articles and other updates.
  • Dependency Injection
  • DI
  • Dependency Inversion
  • IoC
  • Inversion of Control