Dependency Injection in C#: A Complete Guide

Reviewed & published by Brayan K

Master Dependency Injection in C# and ASP.NET Core — DI patterns, service lifetimes, interfaces and containers.

Learn what DI is, why it matters, and how to implement it in modern C# applications.

Introduction

Dependency Injection (DI) is one of the most important concepts in modern C# development. If you're using ASP.NET Core, Unity game engine, MAUI, Blazor, or even WPF — DI is everywhere.

This article will help you understand:

Let's break it down in a simple, beginner-friendly way.

1. What Is Dependency Injection?

To understand DI, first understand the concept of dependency.

A Dependency = Something a class needs to function.

class EmailService
{
    public void Send(string message) {}
}

class UserController
{
    private readonly EmailService _emailService;

    public UserController()
    {
        _emailService = new EmailService();
    }
}

Dependency Injection fixes this.

Instead of creating the dependency inside the class…

You inject the dependency from outside:

class UserController
{
    private readonly IEmailService _emailService;

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

Now the class is:

2. Why Use Dependency Injection?

1. Makes Testing Easy

You can inject fake or mock objects:

var fakeEmail = new FakeEmailService();
var controller = new UserController(fakeEmail);

2. Promotes Loose Coupling

Your class no longer chooses its own dependencies — they are given to it.

3. Improves Code Reusability

Classes are more modular.

4. Standard in ASP.NET Core

Every controller, middleware, and service uses DI by default.

5. Follows SOLID Principles

Mainly OCP (Open/Closed) and DIP (Dependency Inversion Principle).

3. Constructor Injection (Most Common)

public class PaymentController
{
    private readonly IPaymentProcessor _processor;

    public PaymentController(IPaymentProcessor processor)
    {
        _processor = processor;
    }

    public void Pay() => _processor.Process();
}

This is the preferred method in most C# applications.

4. Method Injection

void ProcessOrder(IEmailService emailService)
{
    emailService.Send("Order confirmed");
}

Useful for rarely-used dependencies.

5. Property Injection

public ICacheService CacheService { get; set; }

Less common, used in frameworks where setter injection is needed.

6. Using Dependency Injection in ASP.NET Core

ASP.NET Core has a powerful built-in DI system.

You register services in Program.cs:

builder.Services.AddTransient<IEmailService, EmailService>();
builder.Services.AddScoped<IUserRepository, UserRepository>();
builder.Services.AddSingleton<ILogger, Logger>();
LifetimeMeaningExample Use
TransientNew instance each timeLightweight services
ScopedOne instance per HTTP requestRepository classes
SingletonOne instance for whole appLogging, caching
public class AuthController : ControllerBase
{
    private readonly IUserRepository _repo;

    public AuthController(IUserRepository repo)
    {
        _repo = repo;
    }
}
public async Task Invoke(HttpContext context, ILogger logger)
@inject IEmailService EmailService

7. DI Using Interfaces (Best Practice)

Always inject interfaces, not concrete classes.

public UserController(EmailService service)
public UserController(IEmailService service)

8. DI Containers Available in C#

ASP.NET Core includes a built-in DI container, but other popular ones include:

Easy to use, slower performance.

Used heavily in game engine Unity.

Most modern apps stick with the built-in DI system unless advanced features are needed.

9. Real-World Example: Logging System

public interface ILoggerService
{
    void Log(string message);
}
public class FileLogger : ILoggerService
{
    public void Log(string message) =>
        File.AppendAllText("log.txt", message);
}

Use in your class:

public class OrderService
{
    private readonly ILoggerService _logger;

    public OrderService(ILoggerService logger)
    {
        _logger = logger;
    }

    public void CreateOrder()
    {
        _logger.Log("Order created");
    }
}
builder.Services.AddSingleton<ILoggerService, FileLogger>();

10. Summary

Dependency Injection is essential for clean and scalable C# architecture.

If you're building any modern C# project — from APIs to games — DI will be one of your most-used patterns.

Related articles

Related lessons