Dependency Injection in dotnet-01.Introduction

The example code in this article uses .NET 6, and the specific code can be obtained from this repository Articles.DI.

Let's take a look at this simple code:

public class MessageWriter {
	public void Write(string message) => Console.WriteLine(message);

public class Worker : BackgroundService {
	private readonly MessageWriter _msgWriter = new MessageWriter();

	protected override async Task ExecuteAsync(CancellationToken stoppingToken) {
		while (!stoppingToken.IsCancellationRequested) {
			_msgWriter.Write($"Worker running at: {DateTime.Now}");
			await Task.Delay(1000, stoppingToken);

In the above code, the Worker class contains an instance member of the MessageWriter class, which creates and directly depends on the MessageWriter class. This code has some issues:

  • If the _msgWriter variable needs to be replaced with a different type of implementation, the Worker class needs to be modified.
  • If the MessageWriter class has other dependencies, they must be configured in the Worker class.
  • It is difficult to unit test the Worker class.

If there is a unified manager responsible for instantiating the MessageWriter type and then passing it to the classes that require it, the dependency between these two classes can be decoupled, reducing hardcoding. And this is dependency injection.

Dependency Injection and Inversion of Control#

Dependency Injection (DI) is a technique for implementing Inversion of Control (IoC) between classes and their dependencies.

Inversion of Control is a design principle in object-oriented programming that can be used to reduce the degree of coupling between program code. In addition to dependency injection, there is another method of implementing inversion of control called "dependency lookup".

Most programs consist of multiple classes that reference each other and cooperate with each other to implement business logic. This requires each object to obtain references to other services. If this retrieval process is implemented by the object itself, it will lead to high coupling between classes, making it difficult to maintain and debug.

In traditional applications, if Service A needs to obtain Service B, it needs to be instantiated in its own code block. However, if dependency injection is used, Service A only needs to declare the required service, and the external container is responsible for generating the instance, which Service A only needs to receive. The entire process changes from active to passive, reversing the process of obtaining objects, which is the implementation of Inversion of Control.

The following two diagrams show two dependency relationship graphs:

Direct Dependency Relationship

Direct dependency relationship: Class A calls the method of Class B, and Class B calls the method of Class C. Therefore, at compile time, Class A depends on Class B, and Class B depends on Class C.

Inverted Dependency Relationship

After applying dependency inversion, Class A refers to the methods of interface IB, no longer directly dependent on Class B. At compile time, Class A and Class B both refer to interface IB. Compared with the previous direct dependency, the dependency is inverted. The relationship between Class B and Class C is similar.

IoC Decoupling Process

This diagram vividly explains how inversion of control decouples dependencies between services.


Dependency Injection - Wikipedia

Inversion of Control - Wikipedia

Dependency Inversion - Modern ASP.NET Web Applications eBook

Dependency Injection in .NET

Inversion of Control Containers and the Dependency Injection pattern

Understanding Dependency Injection and Inversion of Control

Inversion of Control (IoC) and Dependency Injection (DI)

Ownership of this post data is guaranteed by blockchain and smart contracts to the creator alone.