Dependency Injection (DI): What is it?
A design pattern called Dependency Injection (DI) is used to accomplish loose coupling between classes and their dependencies. Dependencies are injected from the outside, typically by a framework like.NET Core, rather than being created by a class itself. This encourages improved modularity, testability, and maintainability in application design.

Why Use DI?
Improves testability (easily mock dependencies)
Enhances flexibility and maintainability

Supports SOLID principles, especially:

  • Inversion of Control (IoC)
  • Single Responsibility Principle

How DI Works in .NET Core?
.NET Core comes with a built-in IoC container that supports three main service lifetimes:

Lifetime Description Example Use Case
Singleton One instance for the entire application Caching, config, loggers
Scoped One instance per HTTP request User/session-level services
Transient New instance every time it's requested Lightweight, stateless logic

Step-by-Step Example: Injecting a Service
1. Define an Interface

public interface IMessageService
{
    string GetMessage();
}


2. Create a Concrete Implementation
public class HelloMessageService : IMessageService
{
    public string GetMessage()
    {
        return "Hello from DI!";
    }
}


3. Register the Service in the Program.cs (.NET 6+)
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddScoped<IMessageService, HelloMessageService>(); // DI registration


4. Inject the Service in a Controller
[ApiController]
[Route("[controller]")]
public class HomeController : ControllerBase
{
    private readonly IMessageService _messageService;

    public HomeController(IMessageService messageService)
    {
        _messageService = messageService;
    }

    [HttpGet]
    public string Get() => _messageService.GetMessage();
}


Output
GET /home
=> "Hello from DI!"
Real-World Use Case

In a recent project, we used DI to inject:

  • ILoggingService
  • IEmailService
  • IUserRepository

This allowed us to easily swap implementations during unit testing and to mock external services such as SendGrid and SQL Server, enabling a much more testable and scalable architecture.

Summary

  • DI is built into .NET Core via IServiceCollection.
  • Encourages clean, testable, and modular code.
  • Supports different service lifetimes (Singleton, Scoped, Transient).
  • Use constructor injection as the standard approach.