Dependency Injection in .NET Core: Explained in Simple Terms 🚀

Dependency Injection in .NET Core: Explained in Simple Terms 🚀

If you're a new programmer, don't be scared when you hear Dependency Injection. It's actually a very simple concept. Let's understand it in plain English.

🏪 Let's Start with a Shop Story

Imagine you own a mobile phone shop. You have a salesperson who sells phones to customers. After selling a phone, they need to send a message to notify the customer.

❌ Old Way (Has Problems):

public class OrderService
{
    public void ProcessOrder(Order order)
    {
        // The salesperson is handling message sending themselves
        var emailService = new EmailService();
        emailService.SendConfirmation(order.CustomerEmail);
        
        Console.WriteLine("Phone sale completed");
    }
}
        

What's the problem here?

  • The salesperson (OrderService) is taking responsibility for sending messages themselves
  • If you want to switch from SMS to WhatsApp or email later, you'll have to change all the code
  • Testing the code becomes difficult

✅ New Way (The Solution):

Step 1: Create a Contract

// This is like a contract - anyone can do this job if they follow the rules
public interface IEmailService
{
    void SendConfirmation(string email);
}
        

Step 2: Create Classes That Follow the Contract

// For sending emails
public class EmailService : IEmailService
{
    public void SendConfirmation(string email)
    {
        Console.WriteLine($"Email sent to: {email}");
    }
}

// For sending SMS (can be used later)
public class SMSService : IEmailService
{
    public void SendConfirmation(string email)
    {
        Console.WriteLine($"SMS sent to: {email}");
    }
}

// For sending WhatsApp messages (can be used later)
public class WhatsAppService : IEmailService
{
    public void SendConfirmation(string email)
    {
        Console.WriteLine($"WhatsApp message sent to: {email}");
    }
}
        

Step 3: Make the Salesperson's Job Easier

public class OrderService
{
    private readonly IEmailService _emailService;
    
    // We're telling the salesperson which service to use
    public OrderService(IEmailService emailService)
    {
        _emailService = emailService;
    }
    
    public void ProcessOrder(Order order)
    {
        // Now just using the service, no need to know how it works
        _emailService.SendConfirmation(order.CustomerEmail);
        Console.WriteLine("Phone sale completed");
    }
}
        

Step 4: Connect Everything Together

var builder = WebApplication.CreateBuilder(args);

// Telling .NET which service to use for what
builder.Services.AddScoped<IEmailService, EmailService>();
builder.Services.AddScoped<OrderService>();

var app = builder.Build();
        

🔄 What Benefits Do We Get Now?

  1. The salesperson only handles phone sales
  2. Message sending responsibility belongs to someone else
  3. .NET connects everything properly for us
  4. Later if you want SMS instead of email, just change one line: builder.Services.AddScoped<IEmailService, SMSService>();

🎯 How Long Will They Live (Lifetime):

Transient - New every time

builder.Services.AddTransient<IEmailService, EmailService>();
// Like: Using a new paper cup for water every time
        

Scoped - Once requested, use all day

builder.Services.AddScoped<IEmailService, EmailService>();
// Like: Taking one water bottle in the morning and drinking from it all day
        

Singleton - One for everyone

builder.Services.AddSingleton<IEmailService, EmailService>();
// Like: The whole family using one refrigerator
        

💡 Main Benefits:

Separate Responsibilities: Each class does its own job

Easy to Change: Adding new services is simple

Easy Testing: Can test with fake services

Less Coupling: Changing one doesn't break others

Reusable: Same service can be used elsewhere

🎓 Real Example - A Complete App:

// For getting data from database
public interface IUserRepository
{
    User GetUser(int id);
}

public class DatabaseUserRepository : IUserRepository
{
    public User GetUser(int id)
    {
        // Get user data from database
        return new User { Id = id, Name = "John" };
    }
}

// For main business logic
public class UserService
{
    private readonly IUserRepository _userRepository;
    private readonly IEmailService _emailService;

    public UserService(IUserRepository userRepository, IEmailService emailService)
    {
        _userRepository = userRepository;
        _emailService = emailService;
    }

    public void SendWelcomeMessage(int userId)
    {
        var user = _userRepository.GetUser(userId);
        _emailService.SendConfirmation($"Welcome {user.Name}!");
    }
}

// Connecting everything together
builder.Services.AddScoped<IUserRepository, DatabaseUserRepository>();
builder.Services.AddScoped<IEmailService, EmailService>();
builder.Services.AddScoped<UserService>();
        

🎯 Think of it Like This:

Imagine you're the manager of a restaurant:

  • Without DI: The waiter takes orders, cooks food, serves, and handles payment
  • With DI: The waiter takes orders, chef cooks, server brings food, cashier handles payment

Each person has one job, and you can easily replace the chef without affecting the waiter!

🔍 Real-World Analogy:

Your Phone and Charger:

  • Your phone doesn't create its own charger (no DI = bad)
  • You plug in whatever charger you need (DI = good)
  • You can use different chargers (USB-C, Lightning, etc.) with the same phone
  • The phone doesn't care how the charger works, just that it provides power

The way you explain this, it is a blessing for us. Thanks for sharing your valuable thoughts in the easiest way.

Nice Explanation in easy way

To view or add a comment, sign in

More articles by Mehedi Hasan

Others also viewed

Explore content categories