❗You're Using Dependency Injection Wrong - Use THIS Instead


Hey Reader,

Ever tried to choose the perfect weapon for each creature in a dark, spooky forest? Silver bullets for werewolves, garlic for vampires, chainsaws for zombies... but what if you had to pick your weapon before entering the forest? Just like that forest adventure, dependency injection in C# can leave you stuck with the wrong tool when you need it most - unless you know about the Factory Pattern!

Today, I’m breaking down how the Factory Pattern solves real-world dependency injection issues and when to use it instead of conventional DI. If you’re interested in dynamically switching dependencies at runtime (instead of being locked in beforehand), this is for you!

Watch on YouTube 📺

Check out the full tutorial to see how the Factory Pattern saves the day 👇

video preview

The Problem: Static Dependencies in DI

In typical dependency injection, you declare services upfront, which locks in certain dependencies at compile time. Let’s say we’re working with different services to handle weapons:


public interface IWeaponService
{
    string GetWeapon();
}

public class VampireWeaponService : IWeaponService
{
    public string GetWeapon() => "Garlic";
}

public class WerewolfWeaponService : IWeaponService
{
    public string GetWeapon() => "Silver Bullet";
}

public class ZombieWeaponService : IWeaponService
{
    public string GetWeapon() => "Chainsaw";
}

Registered in the Program.cs:

builder.Services.AddScoped<IWeaponService, VampireWeaponService>();

But here’s the catch: this setup only lets you pick one weapon before runtime. That’s fine if you’re only fighting vampires, but if you encounter a zombie with garlic in hand… well, you’re out of luck!

The Factory Pattern Solution

Enter the Factory Pattern! With this approach, we can dynamically choose the right weapon at runtime based on the creature we’re facing. Here’s how it’s done:

Step 1: Define a Factory Interface


public interface IWeaponFactory
{
    IWeaponService Create(string creatureType);
}

Step 2: Implement the Factory


public class WeaponFactory : IWeaponFactory
{
    private readonly IServiceProvider _serviceProvider;

    public WeaponFactory(IServiceProvider serviceProvider)
    {
        _serviceProvider = serviceProvider;
    }

    public IWeaponService Create(string creatureType)
    {
        return creatureType switch
        {
            "Vampire" => _serviceProvider.GetRequiredService(),
            "Werewolf" => _serviceProvider.GetRequiredService(),
            "Zombie" => _serviceProvider.GetRequiredService(),
            _ => throw new ArgumentException("Unknown creature type!")
        };
    }
}

Step 3: Register Services and Factory in Program.cs

builder.Services.AddScoped<VampireWeaponService>();

builder.Services.AddScoped<WerewolfWeaponService>();

builder.Services.AddScoped<ZombieWeaponService>();

builder.Services.AddScoped<IWeaponFactory, WeaponFactory>();

Step 4: Implement in Controller

Here’s how it looks in a simple BattleController with a POST method to select the right weapon:


[ApiController]
[Route("api/[controller]")]
public class BattleController : ControllerBase
{
    private readonly IWeaponFactory _weaponFactory;

    public BattleController(IWeaponFactory weaponFactory)
    {
        _weaponFactory = weaponFactory;
    }

    [HttpPost("fight")]
    public ActionResult Fight(string creatureType)
    {
        var weaponService = _weaponFactory.Create(creatureType);
        var weapon = weaponService.GetWeapon();
        return Ok($"Fighting a {creatureType} with {weapon}!");
    }
}

Now, instead of committing to one weapon upfront, you’re armed for any creature you face! ⚔️


Want More?

Ready to master .NET and Blazor? Join the .NET Web Academy and enjoy 10% off with the code HALLOWEEN24 until Friday. Learn from real-world examples and dive deep into patterns that’ll make you a better developer. Just check out the link in the video description and hear what real students have to say!

Happy coding and good luck defeating those creatures! 🧛‍♂️🧟‍♂️

Take care,
Patrick

Patrick God

Become a .NET & Blazor expert with weekly tutorials featuring best practices and the latest improvements, right in your inbox.

Read more from Patrick God
video preview

Hey Reader, You sit down to build an API, add some authentication, and think, “JWT should do the trick.” But then you wonder: What happens if my JWT gets stolen? How do I keep users logged in without compromising security? Sound familiar? In my latest video, I show you how to implement secure JWT authentication with short-lived tokens and refresh tokens in .NET. This setup minimizes risk while keeping the user experience seamless. No fluff - just practical, real-world guidance for building...

Hey Reader, Tired of factories and messy if-else logic in your projects? Since .NET 8, Keyed Services make it easy to handle multiple implementations. No more clutter - just clean, scalable code. In my new video, you’ll see how to dynamically pick services using a key and write code that’s easy to extend. It’s a fresh, modern approach to dependency injection that’ll have you rethinking how you design your APIs. 👉 Watch the video here Wishing you a fantastic start to the new year filled with...

video preview

Hey Reader, You sit down to write an API, and before you know it, you’re knee-deep in controllers, attributes, and boilerplate. Sound familiar? What if you could skip all that and still build a fully functional API - fast? That’s where Minimal APIs in .NET come in. They’re clean and lightweight and make building APIs feel like a breeze. In my latest video, I show you how to set up endpoints step by step and structure everything neatly so your code stays easy to read and scale. No fluff - just...