Blog Dla Programistów C#/.NET

Cześć! Dziś przyjrzymy się jednemu z fundamentalnych mechanizmów we współczesnym programowaniu obiektowym – Dependency Injection (DI). Jeśli chcesz tworzyć kod, który jest łatwiejszy w utrzymaniu, rozszerzaniu i testowaniu, DI jest kluczem. Zobaczysz, jak w praktyce zastosować tę technikę w C#/.NET, aby już od samego początku swojej przygody wprowadzić do projektów dobre praktyki.

Wprowadzenie do Dependency Injection w C#/.NET: Zasady, Przykłady i Najlepsze Praktyki

Co to jest Dependency Injection?


Dependency Injection to wzorzec projektowy, który realizuje tzw. odwrócenie zależności (Dependency Inversion Principle – jedna z zasad SOLID). Polega on na tym, by obiekty nie tworzyły bezpośrednio swoich zależności (np. klas współpracujących), ale otrzymywały je z zewnątrz:

    • Dzięki temu klasy stają się mniej zależne od konkretnych implementacji i można je łatwiej wymieniać lub testować.
    • Kod jest bardziej modułowy i czytelniejszy.
    • Implementacje możemy podmieniać (np. używać różnych wariantów tej samej funkcjonalności), co jest szczególnie przydatne podczas pisania testów jednostkowych.


Prosty przykład w C#


Przyjrzyjmy się sytuacji, w której mamy klasę EmailService, wysyłającą wiadomości:

public interface IEmailService
{
void SendEmail(string to, string subject, string body);
}

public class SmtpEmailService : IEmailService
{
public void SendEmail(string to, string subject, string body)
{
Console.WriteLine($"Wysyłanie emaila przez SMTP do: {to}, temat: {subject}");
// Kod wysyłki wiadomości }
}

Zła praktyka: klasa zależna sama tworzy obiekt SmtpEmailService:

public class UserController
{
private SmtpEmailService _emailService = new SmtpEmailService();

public void RegisterUser(string email)
{
// ... logika rejestracji _emailService.SendEmail(email, "Witamy", "Dziękujemy za rejestrację!");
}
}

Problem? Gdy będziemy chcieli przetestować UserController, a nie chcemy wysyłać prawdziwych emaili, będziemy mieli trudniej, bo UserController jest mocno związany z SmtpEmailService.

Dobra praktyka: wstrzykujemy (inject) zależność przez konstruktor:

public class UserController
{
private readonly IEmailService _emailService;

public UserController(IEmailService emailService)
{
_emailService = emailService;
}

public void RegisterUser(string email)
{
// ... logika rejestracji _emailService.SendEmail(email, "Witamy", "Dziękujemy za rejestrację!");
}
}

Teraz możemy łatwo podmienić IEmailService na np. FakeEmailService podczas testów:

public class FakeEmailService : IEmailService
{
public void SendEmail(string to, string subject, string body)
{
// Udajemy, że wysyłamy email, w rzeczywistości nie robimy nic Console.WriteLine("Symulacja wysyłki emaila (FAKE).");
}
}

// Przykład użycia public static void Main()
{
// Wersja produkcyjna var userController1 = new UserController(new SmtpEmailService());
userController1.RegisterUser("real@user.com");

// Wersja testowa var userController2 = new UserController(new FakeEmailService());
userController2.RegisterUser("test@mock.com");
}


Wbudowany kontener DI w .NET (przykład w aplikacji konsolowej)


Od .NET Core (i nowszych .NET 5+), mamy do dyspozycji wbudowany kontener DI, z którego można skorzystać nawet w aplikacji konsolowej:

using Microsoft.Extensions.DependencyInjection;

class Program
{
static void Main(string[] args)
{
// Konfiguracja kontenera usług var serviceCollection = new ServiceCollection();
serviceCollection.AddTransient<IEmailService, SmtpEmailService>();
serviceCollection.AddTransient<UserController>();

var serviceProvider = serviceCollection.BuildServiceProvider();

// Pobieramy gotowy obiekt UserController z wstrzykniętymi zależnościami var userController = serviceProvider.GetService<UserController>();
userController.RegisterUser("hello@world.com");
}
}

    • AddTransient<IEmailService, SmtpEmailService>() – rejestrujemy, że kiedy w konstruktorze jakaś klasa poprosi o IEmailService, dostanie obiekt SmtpEmailService.
    • AddTransient<UserController>() – rejestrujemy też sam UserController, aby kontener mógł go utworzyć.
    • serviceProvider.GetService<UserController>() – tworzy nam instancję UserController z odpowiednią konfiguracją.

Różne cykle życia

Podczas rejestracji w kontenerze DI możesz wybrać, czy obiekt będzie:
    • Transient – nowa instancja przy każdym wywołaniu.
    • Scoped – pojedyncza instancja w ramach "zakresu" (np. jednego żądania w ASP.NET Core).
    • Singleton – jedna instancja na cały czas życia aplikacji.


Jak to wygląda w ASP.NET Core?


W przypadku projektów ASP.NET Core konstrukcja wygląda podobnie, ale konfigurację DI robimy zwykle w pliku Program.cs (lub dawniej w Startup.cs). Przykład:

var builder = WebApplication.CreateBuilder(args);

// Rejestracja serwisów builder.Services.AddTransient<IEmailService, SmtpEmailService>();
builder.Services.AddTransient<UserController>();

var app = builder.Build();

app.MapGet("/", (UserController userController) =>
{
userController.RegisterUser("user@example.com");
return "Zarejestrowano!";
});

app.Run();

Czasem wystarczy, że w kontrolerze ASP.NETCore poprosisz o parametry w konstruktorze, a DI sam wstrzyknie odpowiednie zależności.


Podsumowanie


Dependency Injection to nie tylko "modne hasło" – to fundament nowoczesnej architektury aplikacji w .NET. Dzięki niemu kod staje się bardziej modułowy, testowalny i przyjazny dla kolejnych programistów, którzy będą z nim pracować.

Jeśli chcesz nauczyć się więcej na temat dobrych praktyk w .NET, poznać wzorce projektowe, tworzyć aplikacje ASP.NET Core czy pracować z bazami danych – polecam Ci moje kompletne szkolenie online: "Zostań Programistą .NET". Znajdziesz tam kompleksowe omówienie nie tylko Dependency Injection, ale wielu innych kluczowych elementów ekosystemu .NET.

Daj znać w komentarzach, jakie są Twoje doświadczenia z Dependency Injection i czy widzisz różnicę w jakości kodu po jego wprowadzeniu.

To wszystkie na dzisiaj. Jeżeli taki artykuł Ci się spodobał, to koniecznie dołącz do mojej społeczności – darmowe zapisy, gdzie będziesz również miał dostęp do dodatkowych materiałów i przede wszystkim bonusów. Do zobaczenia w kolejnym artykule.

Szkolenie Zostań Programistą .NET
Szczegóły == Zostań Programistą .NET ==
Zapisy tylko do piątku do 22:00!
Autor artykułu:
Kazimierz Szpin
Kazimierz Szpin
CTO & Founder - FindSolution.pl
Programista C#/.NET. Specjalizuje się w Blazor, ASP.NET Core, ASP.NET MVC, ASP.NET Web API, WPF oraz Windows Forms.
Autor bloga ModestProgrammer.pl
Dodaj komentarz

Wyszukiwarka

Szkolenie Zostań Programistą .NET
Szczegóły == Zostań Programistą .NET ==
Zapisy tylko do piątku do 22:00!

Zostańmy w kontakcie!

Dołącz do mojej listy mailowej, aby otrzymywać ciekawe informacje ze świata programowania. Dodatkowo będziesz informowany o nowych artykułach na blogu, a także otrzymasz wyjątkowe rabaty na moje kursy i szkolenia.

    Nienawidzę spamu, dlatego będziesz otrzymywał tylko wartościowe maile. Możesz zrezygnować z subskrypcji w dowolnym momencie ✅

    © Copyright 2025 modestprogrammer.pl. Wszelkie prawa zastrzeżone. Regulamin. Polityka prywatności. Design by Kazimierz Szpin
    Serwis wykorzystuje pliki cookies. Korzystając ze strony wyrażasz zgodę na wykorzystywanie plików cookies. dowiedz się więcej.