Dependency Injection (DI) è integrata in .NET moderno — il framework include un contenitore DI che costruisce automaticamente le classi e inietta le loro dipendenze. Registri i servizi (mappando interfacce a implementazioni) e il contenitore le risolve, abilitando codice debolmente accoppiato e testabile. È fondamentale per ASP.NET Core.
Registrazione dei servizi
// in Program.cs — register services with a LIFETIME
builder.Services.AddScoped<IUserRepository, UserRepository>(); // interface → implementation
builder.Services.AddSingleton<ICacheService, CacheService>();
builder.Services.AddTransient<IEmailSender, EmailSender>();
Registri ogni mappatura di servizio collegando un'interfaccia a un'implementazione con una durata di vita. Quindi tutto ciò che dipende dall'interfaccia riceve l'implementazione registrata.
Iniezione nel costruttore (il pattern standard)
public class UserService
{
private readonly IUserRepository _repo;
private readonly IEmailSender _email;
// dependencies are declared in the constructor — the container INJECTS them automatically
public UserService(IUserRepository repo, IEmailSender email)
{
_repo = repo;
_email = email;
}
}
// you never `new UserService(...)` manually — the container builds it, resolving the chain
Le dipendenze sono dichiarate come parametri del costruttore (tipizzate come interfacce); il contenitore costruisce la classe e inietta le implementazioni registrate, risolvendo automaticamente l'intero grafo delle dipendenze.
Durate dei servizi (importante sceglierne una corretta)
Singleton → ONE instance for the entire app lifetime (shared; must be thread-safe)
Scoped → one instance PER request (the common default for web — e.g. DbContext)
Transient → a NEW instance every time it's requested (lightweight, stateless services)
→ Choosing wrong (e.g. a singleton capturing a scoped DbContext) causes subtle bugs.
I vantaggi: accoppiamento loose e testabilità
// because UserService depends on INTERFACES, you can inject MOCKS in tests
var service = new UserService(mockRepo, mockEmail); // no real DB/email needed
Perché è importante
L'iniezione di dipendenze è fondamentale per .NET moderno — è integrata nel framework ed è la spina dorsale di ASP.NET Core, quindi comprenderla è essenziale per qualsiasi sviluppo moderno di applicazioni C#.
Il contenitore DI integrato del framework costruisce automaticamente le classi e inietta le loro dipendenze (risolvendo l'intero grafo delle dipendenze), quindi registri i servizi e lasci che il contenitore colleghi tutto insieme piuttosto che istanziare manualmente le dipendenze.
I vantaggi fondamentali sono significativi e centrali al motivo per cui DI è enfatizzata: accoppiamento loose (dipendere da interfacce anziché da classi concrete, quindi le implementazioni possono essere scambiate) e soprattutto testabilità (iniettare implementazioni mock nei test invece di dipendenze reali come database o servizi email — rendendo i unit test approfonditi pratici).
Comprendere come registrare i servizi (mappando interfacce a implementazioni), iniezione nel costruttore (il pattern standard), e — importantemente — le durate dei servizi (Singleton, Scoped, Transient) è essenziale: scegliere una durata sbagliata causa bug sottili e difficili da debuggare (ad esempio un singleton che contiene un DbContext scoped, o problemi di thread-safety con singleton condivisi), quindi comprendere quando applica ogni durata (Scoped per-richiesta per cose come DbContext, Singleton per servizi condivisi stateless, Transient per quelli leggeri) è critico.
Poiché DI è integrata in .NET, sottende l'architettura di ASP.NET Core, ed è la chiave per scrivere codice debolmente accoppiato e testabile, padroneggiare — il contenitore, iniezione nel costruttore, design basato su interfacce, e soprattutto le durate dei servizi — è importante, conoscenza applicata frequentemente a livello senior per costruire applicazioni C# moderne manutenibili e testabili, ed è un argomento frequente nei colloqui.
