0 0
Read Time:4 Minute, 14 Second

🔍 Introduction

As a new developer, you’ve probably come across a situation where one class creates and controls the behavior of another class, making it tightly coupled and hard to test or extend. This is where Dependency Injection (DI) and Inversion of Control (IoC) come to the rescue.

In this blog, we’ll break down these concepts in simple terms, walk through real-world examples, and implement them using .NET Core, including Entity Framework Core registration in the DI container. We’ll also tackle common follow-up interview questions at the end.


🧠 What is Dependency Injection (DI)?

Dependency Injection is a software design pattern that helps you achieve loose coupling between classes. Instead of a class creating its own dependencies, they are provided from the outside, typically via constructor parameters.

🔌 Think of DI as plugging in different components into a machine instead of soldering them permanently.


🔄 What is Inversion of Control (IoC)?

Inversion of Control is the broader concept behind Dependency Injection. It means handing over the control of object creation to a framework or container. In .NET Core, the built-in IoC container handles object creation, lifetime management, and injection for you.

🧠 IoC = “Don’t call me, I’ll call you.”


⚙️ Types of Dependency Injection in .NET Core

  1. Constructor Injection ✅ (Most common)

  2. Property Injection

  3. Method Injection

We’ll focus on Constructor Injection here.


📦 Real-Time Example: Notification System

Scenario

We need a system to send email notifications. We’ll inject an EmailNotificationService into a controller rather than creating it inside.

Step 1: Define the Interface

public interface INotificationService
{
void Send(string to, string message);
}

Step 2: Implement the Service

public class EmailNotificationService : INotificationService
{
public void Send(string to, string message)
{
Console.WriteLine($"Email sent to {to}: {message}");
}
}

Step 3: Inject into Controller

public class NotificationController : ControllerBase
{
private readonly INotificationService _notificationService;
public NotificationController(INotificationService notificationService)
{
_notificationService = notificationService;
}[HttpPost] public IActionResult NotifyUser(string email, string message)
{
_notificationService.Send(email, message);
return Ok(“Notification sent!”);
}
}


Step 4: Register in Program.cs

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddScoped<INotificationService, EmailNotificationService>();
var app = builder.Build();


🗃️ How Do You Register EF Core in the DI Container?

Entity Framework Core’s DbContext is also a dependency and must be registered in the DI container:

Sample ApplicationDbContext

public class ApplicationDbContext : DbContext
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options) { }
public DbSet<User> Users { get; set; }
}

Registering EF Core in Program.cs

builder.Services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection")));

🧪 Unit Test Example with Moq

public class NotificationControllerTests
{
[Fact] public void NotifyUser_SendsEmail_ReturnsOk()
{
var mockService = new Mock<INotificationService>();
var controller = new NotificationController(mockService.Object);
var result = controller.NotifyUser(“test@example.com”, “Welcome!”);Assert.IsType<OkObjectResult>(result);
}
}


🖼️ Visual Diagram – DI with IoC Container


✅ Benefits of Dependency Injection and IoC

Feature Benefit
🧩 Loose Coupling Components depend on abstractions, not concrete classes.
🧪 Testability Easier to write unit tests with mocks/fakes.
🔁 Flexibility Swap implementations without changing dependent classes.
🧼 Clean Code Keeps classes focused and readable.
🔍 Debuggability Isolated testing simplifies debugging.

❓ Interview Follow-Up Questions & Answers

🔹 Normal Questions

Q1: What is the difference between IoC and DI?
👉 IoC is the principle of delegating control to a container. DI is one implementation of IoC, where dependencies are provided from the outside.

Q2: Why is constructor injection preferred?
👉 It makes dependencies mandatory and explicit. It’s also easier for testing and ensures the object is always initialized properly.

Q3: What are the lifetimes of services in .NET Core?

  • Transient: New instance every time.

  • Scoped: One instance per request.

  • Singleton: One instance for the app’s lifetime.

Q4: How do you register multiple implementations of the same interface?

builder.Services.AddTransient<INotificationService, EmailNotificationService>();
builder.Services.AddTransient<INotificationService, SmsNotificationService>();

You can inject IEnumerable<INotificationService> to resolve both.

Q5: What is the default IoC container in .NET Core?
👉 Microsoft.Extensions.DependencyInjection is the built-in default IoC container.


🔹 Tricky Questions

Q6: Can you inject a service inside another injected service?
👉 Yes. The DI container supports nested dependencies and will resolve the full dependency tree.

Q7: What happens if you inject a scoped service into a singleton?
👉 It causes a runtime exception. Scoped services cannot be safely injected into singletons. You should use IServiceProvider or a factory pattern instead.

Q8: How would you resolve dependencies dynamically at runtime?
👉 You can use IServiceProvider.GetService<T>() or ActivatorUtilities.

Q9: How can you replace a service at runtime (e.g., in integration tests)?
👉 Use the ConfigureTestServices() method in WebApplicationFactory or use Replace() extension from Microsoft.Extensions.DependencyInjection.Abstractions.

Q10: What if a dependency has its own dependencies?
👉 The IoC container recursively resolves all nested dependencies automatically.


🎯 Summary

  • Dependency Injection enables decoupled and testable designs.

  • IoC delegates object creation to a container.

  • .NET Core makes it easy with a built-in DI system.

  • EF Core registration and service lifetimes are crucial for robust application architecture.


📢 Final Thoughts

Mastering Dependency Injection and IoC is essential for modern .NET developers. It’s not just about patterns — it’s about building clean, flexible, testable, and maintainable systems.

Previous post Murphy’s Law: Why You Need That Emergency Fund Before the New Phone
Next post Service Lifetimes in .NET Core – With Real-Time Examples & Interview Q&A
Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Close
0
Would love your thoughts, please comment.x
()
x
× How can I help you?