Uno dei problemi più comuni nello sviluppo di applicazioni distribuite è la gestione della configurazione. Connection string, variabili d’ambiente, secret, endpoint: tutto deve essere mantenuto coerente tra progetti e ambienti (locale, test, produzione). Senza una strategia chiara, il rischio di errori è altissimo.
.NET Aspire affronta questo problema con un approccio centralizzato e dichiarativo, che semplifica drasticamente la gestione delle dipendenze. In questo articolo vedremo come funziona, con esempi pratici.
Il problema della configurazione distribuita
Immagina di avere:
Senza Aspire, dovresti:
Con Aspire, invece, definisci tutto una volta sola nell’AppHost, e sarà lui a propagare la configurazione ai progetti.
Connection string centralizzate
Vediamo un esempio con un database Postgres:
var builder = DistributedApplication.CreateBuilder(args);
// Aggiungiamo Postgres var postgres = builder.AddPostgres("postgres") .WithDataVolume() .AddDatabase("appdb");
// API collegata al DB builder.AddProject<Projects.MyApi>("api") .WithReference(postgres);
builder.Build().Run();
In questo esempio, l’AppHost crea una risorsa postgres e un database appdb. Automaticamente, l’API riceve una connection string chiamata appdb.
Dentro il progetto MyApi, la connection string è accessibile tramite IConfiguration:
var builder = WebApplication.CreateBuilder(args);
// Recuperiamo la connessione var connectionString = builder.Configuration.GetConnectionString("appdb");
builder.Services.AddDbContext<AppDbContext>(options => options.UseNpgsql(connectionString));
Non abbiamo scritto manualmente nessuna connection string: Aspire si occupa di generarla e passarla al progetto.
Variabili d’ambiente
Allo stesso modo, Aspire può fornire variabili d’ambiente ai progetti. Ad esempio:
var api = builder.AddProject<Projects.MyApi>("api");
api.WithEnvironment("FeatureX__Enabled", "true");
Il progetto MyApi riceverà la variabile FeatureX__Enabled=true, che può essere letta come una normale configurazione .NET:
var featureXEnabled = builder.Configuration.GetValue<bool>("FeatureX:Enabled");
Gestione dei secret
Un aspetto critico della configurazione sono i secret (password, token, API key). Aspire incoraggia a non hardcodarli mai. Puoi invece dichiararli come secret nell’AppHost.
Ad esempio, per aggiungere una chiave API:
var api = builder.AddProject<Projects.MyApi>("api");
api.WithSecret("ApiKeys:ExternalService");
Nel progetto, leggerai la configurazione normalmente:
var apiKey = builder.Configuration["ApiKeys:ExternalService"];
In locale, Aspire ti chiederà di inserire il valore la prima volta e lo salverà in modo sicuro, senza scriverlo in chiaro nei file di progetto.
Un esempio completo
Immaginiamo un sistema con:
Ecco come potrebbe apparire l’AppHost:
var builder = DistributedApplication.CreateBuilder(args);
var postgres = builder.AddPostgres("postgres") .WithDataVolume() .AddDatabase("appdb");
var api = builder.AddProject<Projects.MyApi>("api") .WithReference(postgres) .WithSecret("ApiKeys:ExternalService");
builder.AddProject<Projects.MyFrontend>("frontend") .WithReference(api) .WithEnvironment("Frontend__Theme", "dark");
builder.Build().Run();
Risultato:
Cosa fa Aspire dietro le quinte
In questi esempi, Aspire svolge una serie di compiti che normalmente richiederebbero molto lavoro manuale:
In questo modo, Aspire riduce al minimo il rischio di inconsistenze tra ambienti e semplifica enormemente la gestione della configurazione.
Conclusioni
La configurazione è spesso una delle parti più delicate nello sviluppo di applicazioni distribuite. Con Aspire, invece, diventa un aspetto quasi trasparente: definisci tutto nell’AppHost e lasci che sia il framework a occuparsi della distribuzione delle impostazioni ai singoli progetti.
Questo approccio migliora la sicurezza (grazie ai secret gestiti centralmente), la produttività (meno duplicazione) e la coerenza tra ambienti diversi.
Nel prossimo articolo parleremo di Aspire e il Cloud Native, per vedere come questa architettura si integra naturalmente con container, orchestratori e servizi cloud.
Spoiler alert : Articolo scrito con il supporto dell'intelligenza artificiale