DotNet — Cheat Sheet

Tag: csharp, dotnet, clr, aspnetcore, efcore, memory-management

Livello: intermedio

TL;DR: Runtime CLR, gestione memoria con Garbage Collector (generazioni 0, 1, 2 e LOH), pattern async/await su ThreadPool e architettura ASP.NET Core con Dependency Injection nativa.

Concetti chiave

Common Language Runtime (CLR) gestisce esecuzione, JIT compilation, garbage collection e sicurezza dei tipi.

Common Type System (CTS) definisce i tipi supportati; Common Language Specification (CLS) garantisce interoperabilità tra linguaggi.

Value types allocati sullo stack o inline negli oggetti; Reference types allocati su managed heap.

Garbage Collector a tre generazioni (Gen 0, Gen 1, Gen 2) più Large Object Heap (LOH per oggetti >= 85.000 byte).

Pattern async/await non blocca thread; rilascia thread al ThreadPool durante operazioni di I/O asincrone.

Dependency Injection nativa con tre cicli di vita: Transient (nuova istanza sempre), Scoped (per richiesta HTTP), Singleton (unica istanza).

Middleware pipeline in ASP.NET Core gestisce request e response in ordine sequenziale bidirezionale.

Entity Framework Core supporta tracking query e as-no-tracking per ottimizzare letture in sola consultazione.

IDisposable e statement using rilasciano risorse unmanaged (handle SO, connessioni DB, socket) in modo deterministico.

Kestrel funge da web server HTTP cross-platform ad alte prestazioni predefinito per ASP.NET Core.

Domande tipiche e risposte pronte

Q: Qual è la differenza tra string e StringBuilder?R: string è immutabile e ogni concatenazione alloca un nuovo oggetto sul managed heap. StringBuilder modifica un buffer interno mutabile, riducendo drasticamente le allocazioni e la pressione sul Garbage Collector in scenari di concatenazione intensiva.

Q: Quando si usa ValueTask<T> invece di Task<T>?R: Uso ValueTask<T> quando l'operazione asincrona si completa frequentemente in modo sincrono o da cache, evitando l'allocazione dell'oggetto Task sull'heap nel path sincrono ad alto throughput.

Q: Come funziona il Garbage Collector in .NET?R: Il GC è generazionale e mark-and-sweep: Gen 0 per oggetti a vita breve, Gen 1 come transizione, Gen 2 per lunga durata; scatta quando le soglie di memoria vengono superate per compattare e liberare l'heap.

Q: Che differenza c'è tra un servizio Scoped e uno Transient in ASP.NET Core?R: Un servizio Transient crea una nuova istanza ogni volta che viene richiesto dal container; uno Scoped crea una sola istanza per l'intero ciclo di vita di una singola richiesta HTTP.

Insidie e errori comuni

Cattiva gestione delle connessioni: istanziare manualmente HttpClient invece di usare IHttpClientFactory causa socket exhaustion.

Blocco del thread asincrono con .Result o .Wait(), provocando thread pool starvation o deadlock.

Modifica concorrente di collezioni non thread-safe (come List<T> o Dictionary<TKey, TValue>) senza sync o classi concurrent.

Captive Dependency: iniettare un servizio Scoped dentro un Singleton estende la vita dello Scoped per tutta l'applicazione.

Mancata chiamata a Dispose() su stream o file handle non incapsulati in blocchi using.

N+1 query problem in EF Core per mancato utilizzo di eager loading con .Include().

Snippet e comandi

# Comandi CLI frequenti
dotnet new webapi -n ApiService
dotnet build -c Release
dotnet run --project ApiService
dotnet test
dotnet add package Microsoft.EntityFrameworkCore

C#

// Registrazione lifecycle e middleware minimale
var builder = WebApplication.CreateBuilder(args);

builder.Services.AddTransient<ITransientService, TransientService>();
builder.Services.AddScoped<IScopedService, ScopedService>();
builder.Services.AddSingleton<ISingletonService, SingletonService>();

var app = builder.Build();

app.Use(async (context, next) =>
{
    // Esecuzione pre-elaborazione
    await next();
    // Esecuzione post-elaborazione
});

app.MapGet("/items/{id}", async (int id, IScopedService service) =>
{
    var item = await service.GetByIdAsync(id);
    return item is not null ? Results.Ok(item) : Results.NotFound();
});

app.Run();

Da ripassare

[ ] Pattern di allocazione e frammentazione su Large Object Heap (LOH)

[ ] Implementazione e semantica del Dispose Pattern con GC.SuppressFinalize

[ ] Memory e Span per manipolazione dati ad alte prestazioni senza allocazioni

[ ] Differenze architetturali tra .NET Framework, .NET Core e .NET 8/9

[x] Cicli di vita dei servizi in ASP.NET Core Dependency Injection

[x] Utilizzo base di async, await e Task cancellation token

Jarvis Interviews
Jarvis