Friday, November 7, 2025

Dotnet Core - Dependency Injection (DI)

 ๐Ÿงฉ What is Dependency Injection (DI)?

Dependency Injection (DI) is a design pattern used to achieve loose coupling between classes and their dependencies.

In simple terms:

Instead of a class creating its own dependencies, they are provided (injected) from the outside — typically by a framework or container.

 




๐Ÿง  Example Without DI (Tight Coupling)

public class NotificationService { private readonly EmailService _emailService = new EmailService(); public void Notify(string message) { _emailService.Send(message); } }

Here:

  • NotificationService directly depends on EmailService.
  • If we want to replace EmailService with, say, SmsService, we must change the code inside NotificationService.


✅ Example With DI (Loose Coupling)

public interface IMessageService { void Send(string message); } public class EmailService : IMessageService { public void Send(string message) => Console.WriteLine($"Email: {message}"); } public class NotificationService { private readonly IMessageService _messageService; // Dependency is injected via constructor public NotificationService(IMessageService messageService) { _messageService = messageService; } public void Notify(string message) { _messageService.Send(message); } }

Now you can plug in any implementation (Email, SMS, Push) without changing NotificationService.


๐Ÿงฑ Dependency Injection in .NET Core

.NET Core has built-in support for Dependency Injection via the Microsoft.Extensions.DependencyInjection namespace.

You configure DI inside the Program.cs or Startup.cs (depending on .NET version).


๐Ÿงฐ Typical .NET Core DI Setup

Example — in Program.cs (.NET 6/7/8 minimal hosting model)

var builder = WebApplication.CreateBuilder(args);

// 1️⃣ Register services in DI container builder.Services.AddScoped<IMessageService, EmailService>(); builder.Services.AddScoped<NotificationService>(); var app = builder.Build(); // 2️⃣ Resolve and use service app.MapGet("/notify", (NotificationService service) => { service.Notify("Hello, .NET Core DI!"); return "Notification Sent!"; }); app.Run();

๐Ÿ” How DI Works in .NET Core

When you run the app:

  1. The service container is created by WebApplication.CreateBuilder.

  2. Services are registered using builder.Services.Add...().

  3. When a class (e.g., controller, page, or middleware) requests a dependency, the DI container creates and injects it automatically.


๐Ÿ”„ Service Lifetimes

LifetimeDescriptionUse Case
TransientNew instance created every time it’s requestedLightweight, stateless services
ScopedOne instance per request (HTTP scope)Web request-specific services
SingletonSingle instance for the entire app lifetimeConfiguration, caching, logging

Example:

builder.Services.AddTransient<IEmailService, EmailService>(); builder.Services.AddScoped<IUserService, UserService>(); builder.Services.AddSingleton<ILoggingService, LoggingService>();

๐Ÿง  DI Example in ASP.NET Core Controller

public interface ICustomerService { IEnumerable<string> GetCustomers(); } public class CustomerService : ICustomerService { public IEnumerable<string> GetCustomers() => new[] { "John", "Jane" }; } [ApiController] [Route("[controller]")] public class CustomerController : ControllerBase { private readonly ICustomerService _service; // Dependency is injected automatically public CustomerController(ICustomerService service) { _service = service; } [HttpGet] public IActionResult Get() { return Ok(_service.GetCustomers()); } }

✅ ASP.NET Core automatically injects CustomerService because it was registered in the DI container.


⚙️ Advanced DI Topics

1️⃣ Constructor Injection (most common)

Dependencies passed via constructor.

2️⃣ Method Injection

Dependencies passed as method parameters.

public void SendNotification([FromServices] IMessageService service) { service.Send("Message"); }

3️⃣ Property Injection

Dependency assigned via property (not common in .NET Core DI by default).


๐Ÿ”ฉ Built-in DI Container Features

  • Open Generics Support
    builder.Services.AddScoped(typeof(IRepository<>), typeof(Repository<>));

  • Service Replacement:  Simply remove MyService registration with IMyService and add new registration MyMockService with IMyService.
    This is useful when you are using some library and that has registered IMyService with MyService, so now Replace statement will replace all previous registration with new one.

    builder.Services.AddSingleton<IMyService, MyService>();
    builder.Services.Replace(ServiceDescriptor.Singleton<IMyService, MyMockService>());

  • Configuration + Options Pattern
    builder.Services.Configure<MyConfig>(builder.Configuration.GetSection("MySection"));


๐Ÿงฐ DI in Non-Web .NET Apps

You can also use DI in:

  • Console apps
  • Worker services
  • Background jobs

Example:

var services = new ServiceCollection(); services.AddScoped<IMessageService, EmailService>(); var provider = services.BuildServiceProvider(); var messageService = provider.GetRequiredService<IMessageService>(); messageService.Send("Hello from Console App!");

๐Ÿ’ก Benefits of Using DI

BenefitDescription
Loose CouplingEasier to swap implementations
TestabilityUse mocks in unit tests easily
ReusabilityServices can be reused across components
MaintainabilityReduces hard-coded dependencies
ScalabilityCentralized lifecycle management

⚠️ Common Pitfalls

MistakeImpact
Registering service with wrong lifetimeMemory leaks or inconsistent behavior
Creating new instances manually inside serviceBreaks DI chain
Overusing SingletonCan cause thread-safety issues
Circular dependenciesTwo services depend on each other — runtime error

๐Ÿงพ Summary

AspectDetails
PatternDependency Injection (DI)
Built-in ContainerMicrosoft.Extensions.DependencyInjection
Registration MethodsAddSingleton, AddScoped, AddTransient
GoalLoose coupling, better testability, and flexibility
Injection MethodsConstructor (primary), Method, Property
Used InASP.NET Core, Worker Services, Blazor, Console Apps

No comments:

Post a Comment

CI/CD - Safe DB Changes/Migrations

Safe DB Migrations means updating your database schema without breaking the running application and without downtime . In real systems (A...