.NET  

Understanding Dependency Injection in .NET with Practical Examples

Introduction

Dependency Injection (DI) is one of the most important concepts in modern .NET development. It helps developers write loosely coupled, testable, and maintainable code. With the introduction of .NET Core and later .NET versions, Dependency Injection is built into the framework, making it easy to implement without third-party libraries.

In this article, we will understand:

  • What Dependency Injection is

  • Why do we need it

  • Types of Dependency Injection

  • How to implement DI in .NET with real examples

What Is Dependency Injection?

Dependency Injection is a design pattern where an object receives its dependencies from an external source rather than creating them itself.

Without Dependency Injection

public class EmailService
{
    public void SendEmail(string message)
    {
        Console.WriteLine("Email sent: " + message);
    }
}

public class Notification
{
    private EmailService _emailService = new EmailService();

    public void Notify()
    {
        _emailService.SendEmail("Hello User");
    }
}

Problems with This Approach

  • Tight coupling between classes

  • Difficult to unit test

  • Hard to replace or extend functionality

Dependency Injection Approach

With Dependency Injection, dependencies are injected, not created.

public interface IEmailService
{
    void SendEmail(string message);
}

public class EmailService : IEmailService
{
    public void SendEmail(string message)
    {
        Console.WriteLine("Email sent: " + message);
    }
}

public class Notification
{
    private readonly IEmailService _emailService;

    public Notification(IEmailService emailService)
    {
        _emailService = emailService;
    }

    public void Notify()
    {
        _emailService.SendEmail("Hello User");
    }
}

Built-In Dependency Injection in .NET

.NET provides a built-in DI container through Microsoft.Extensions.DependencyInjection.

Registering Services

In Program.cs:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddScoped<IEmailService, EmailService>();
builder.Services.AddScoped<Notification>();

var app = builder.Build();

Using the Service

public class HomeController : Controller
{
    private readonly Notification _notification;

    public HomeController(Notification notification)
    {
        _notification = notification;
    }

    public IActionResult Index()
    {
        _notification.Notify();
        return View();
    }
}

Types of Dependency Injection

1. Constructor Injection (Recommended)

  • Dependencies are provided through the constructor

  • Most commonly used in .NET

2. Property Injection

  • Dependencies are set through public properties

  • Less preferred due to optional dependencies

3. Method Injection

  • Dependencies are passed through method parameters

  • Useful in specific scenarios

Service Lifetimes in .NET

.NET supports three service lifetimes:

1. Transient

  • New instance every time

builder.Services.AddTransient<IEmailService, EmailService>();

2. Scoped

  • One instance per request (recommended for web apps)

builder.Services.AddScoped<IEmailService, EmailService>();

3. Singleton

  • One instance for the entire application

builder.Services.AddSingleton<IEmailService, EmailService>();

Advantages of Dependency Injection

  • Loose coupling

  • Improved testability

  • Better code maintainability

  • Easy to extend and modify

  • Built-in support in .NET

Conclusion

Dependency Injection is a core concept every .NET developer should master. With built-in support in modern .NET, implementing DI is straightforward and highly beneficial. By following DI principles, your applications become cleaner, more testable, and easier to maintain.