🌐 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

πŸ€– Copilot vs Microsoft Copilot vs Copilot Studio: What’s the Difference?

Understanding Auto-Numbering in a Multi-Transaction System

Integrating Dynamics 365 CRM with MuleSoft Using a Synchronous C# Plugin