🌐 Understanding Dependency Injection in .NET — A Beginner-Friendly Guide

 


If you’ve worked with .NET, you’ve likely heard about Dependency Injection (DI). While it may sound technical, DI is simply a way of writing code that’s cleaner, easier to test, and more flexible.

Let’s break it down with real examples and explanations — including a working sample at the end.


🧠 What Is Dependency Injection?

Imagine you’re at a coffee shop. Instead of making your own coffee, you just ask the barista — you depend on them to get the job done.

Similarly, in code, instead of creating your own objects, you ask a container (like a barista) to provide what you need.

That’s Dependency Injection.


🔧 The Building Blocks of DI in .NET

.NET provides a built-in way to do DI through these components:

✔️ IServiceCollection

This is where you register the services your app will use.

✔️ IServiceProvider

This is the service factory that creates and delivers your services when needed.

✔️ ServiceDescriptor

A description of a service that includes:

  • The type (e.g., IGreetingService)

  • The implementation (e.g., DefaultGreetingService)

  • The lifetime (Singleton, Scoped, or Transient)


🔄 Common Lifetimes

LifetimeDescription
SingletonOne instance for the entire app
ScopedOne instance per request (in web apps)
TransientNew instance every time it's requested

🛠 Real Example: DI in Action

Here’s a complete working example that shows how everything ties together:


using Microsoft.Extensions.DependencyInjection; // 1. Create the service collection. var services = new ServiceCollection(); // 2. Register (add and configure) the services. services.AddSingleton<IConsole>( implementationFactory: static _ => new DefaultConsole { IsEnabled = true }); services.AddSingleton<IGreetingService, DefaultGreetingService>(); services.AddSingleton<FarewellService>(); // 3. Build the service provider from the service collection. var serviceProvider = services.BuildServiceProvider(); // 4. Resolve the services that you need. var greetingService = serviceProvider.GetRequiredService<IGreetingService>(); var farewellService = serviceProvider.GetRequiredService<FarewellService>(); // 5. Use the services var greeting = greetingService.Greet("David"); var farewell = farewellService.SayGoodbye("David");

🔍 Let’s Break Down the Code

1️⃣ new ServiceCollection();

This creates a container where you register all the services your app will use.

2️⃣ services.AddSingleton<IConsole>(_ => new DefaultConsole { IsEnabled = true });

You are telling .NET:

"Whenever someone needs IConsole, give them this specific DefaultConsole where IsEnabled is set to true."

This uses a lambda function to customize how the service is created.

3️⃣ services.AddSingleton<IGreetingService, DefaultGreetingService>();

This registers an interface-to-class mapping. If someone asks for IGreetingService, they’ll get an instance of DefaultGreetingService.

4️⃣ BuildServiceProvider();

This finalizes your service collection and builds a provider that can deliver services as needed.

5️⃣ GetRequiredService<T>();

This gets an instance of the service you registered. In our case:

  • IGreetingService for greetings

  • FarewellService for goodbyes


💬 Interfaces and Implementations Used

IConsole and DefaultConsole

public interface IConsole { void WriteLine(string message); } public class DefaultConsole : IConsole { public bool IsEnabled { get; set; } = true; public void WriteLine(string message) { if (IsEnabled) Console.WriteLine(message); } }

IGreetingService and DefaultGreetingService


public interface IGreetingService { string Greet(string name); } public class DefaultGreetingService : IGreetingService { private readonly IConsole _console; public DefaultGreetingService(IConsole console) { _console = console; } public string Greet(string name) { var message = $"Hello, {name}!"; _console.WriteLine(message); return message; } }

FarewellService


public class FarewellService { private readonly IConsole _console; public FarewellService(IConsole console) { _console = console; } public string SayGoodbye(string name) { var message = $"Goodbye, {name}!"; _console.WriteLine(message); return message; } }

✅ Summary

  • Dependency Injection helps you build loosely-coupled, testable, and maintainable code.

  • .NET provides everything you need via Microsoft.Extensions.DependencyInjection.

  • You register services with lifetimes and resolve them when needed.

  • Customizing services with lambdas allows for more flexibility — like configuring IsEnabled.

Comments

Popular posts from this blog

🔍 Dataverse + Azure Integration: Choosing Between Synapse Link and Microsoft Fabric

⚡ Example: Rate Limiting in Azure API Management

👤 Anonymous Role in Power Pages – What It Is and When to Use It