Uno degli obiettivi principali di .NET Aspire è rendere lo sviluppo cloud native più accessibile. Creare applicazioni distribuite pensate per il cloud non significa solo scrivere codice, ma anche gestire container, orchestratori, networking, secret, osservabilità e molto altro.
Senza strumenti adeguati, la curva di complessità cresce rapidamente. Aspire affronta questa sfida permettendoti di sviluppare applicazioni in locale utilizzando un application model dichiarativo, già pronto per essere eseguito in container o integrato con servizi gestiti nel cloud.
Il termine cloud native viene spesso associato a Kubernetes, Docker o microservizi, ma il concetto è più ampio. Secondo la Cloud Native Computing Foundation, un’applicazione cloud native dovrebbe essere:
Con Aspire, molti di questi aspetti vengono gestiti in automatico o fortemente semplificati, soprattutto nelle fasi di sviluppo e integrazione tra componenti.
Vediamo un esempio concreto. Immaginiamo un progetto Aspire composto da un’API e da una cache Redis in locale:
var builder = DistributedApplication.CreateBuilder(args);
var redis = builder.AddContainer("redis", "redis:7.2")
.WithEndpoint("tcp", 6379);
builder.AddProject<Projects.MyApi>("api")
.WithReference(redis);
builder.Build().Run();
In questo scenario, Aspire:
Non è necessario scrivere file docker-compose.yml o configurazioni manuali: l’AppHost descrive la topologia dell’applicazione e Aspire si occupa dell’orchestrazione locale.
Quando si passa dal locale al cloud, Aspire mette a disposizione package specifici per l’utilizzo delle risorse cloud, come database gestiti, cache o servizi di messaging. Queste risorse vengono dichiarate direttamente nell’AppHost e fanno parte dello stesso application model utilizzato durante lo sviluppo locale.
In fase di sviluppo, è comune utilizzare container locali per simulare le dipendenze esterne dell’applicazione. Negli ambienti cloud, invece, le stesse dipendenze possono essere rappresentate da servizi gestiti, come Azure Cache for Redis, mantenendo invariato il modo in cui l’applicazione le consuma.
La scelta tra una risorsa eseguita in container o una risorsa cloud viene quindi definita nell’AppHost, in base all’ambiente di esecuzione. Ad esempio, possiamo utilizzare Redis in container durante lo sviluppo locale e passare a un servizio gestito negli ambienti non locali:
var builder = DistributedApplication.CreateBuilder(args);
IResourceBuilder<RedisResource> redis;
if (builder.Environment.IsDevelopment())
{
redis = builder.AddContainer("redis", "redis:7.2")
.WithEndpoint("tcp", 6379);
}
else
{
redis = builder.AddAzureRedis("redis");
}
builder.AddProject<Projects.MyApi>("api")
.WithReference(redis);
builder.Build().Run();
Dal punto di vista dell’API, nulla cambia: l’applicazione riceve sempre una connection string associata alla risorsa logica redis.
Ciò che cambia è l’implementazione della risorsa, non il modo in cui viene consumata.
Questo approccio consente di sviluppare e testare l’applicazione in locale con container leggeri e, successivamente, collegarla a servizi cloud gestiti, senza modificare il codice applicativo.
Per chi lavora con Kubernetes, Aspire offre anche la possibilità di esportare automaticamente la definizione dell’applicazione in manifest YAML.
Poiché Aspire conosce già la topologia dell’applicazione (progetti, dipendenze, risorse e binding), può generare deployment, service e secret riducendo il lavoro manuale e il rischio di configurazioni incoerenti.
Immaginiamo ora un sistema composto da:
MyApi);MyFrontend);La definizione nell’AppHost potrebbe essere la seguente:
var builder = DistributedApplication.CreateBuilder(args);
var sql = builder.AddSqlServer("sql")
.WithDataVolume()
.AddDatabase("appdb");
IResourceBuilder<RedisResource> redis;
if (builder.Environment.IsDevelopment())
{
redis = builder.AddContainer("redis", "redis:7.2")
.WithEndpoint("tcp", 6379);
}
else
{
redis = builder.AddAzureRedis("redis");
}
var api = builder.AddProject<Projects.MyApi>("api")
.WithReference(sql)
.WithReference(redis);
builder.AddProject<Projects.MyFrontend>("frontend")
.WithReference(api);
builder.Build().Run();
Con questa configurazione:
Ancora una volta, il codice dei progetti applicativi resta invariato.
In scenari come questo, Aspire si occupa di diversi aspetti fondamentali per lo sviluppo cloud native:
Aspire consente quindi di mantenere il focus sul codice applicativo, riducendo al minimo la complessità infrastrutturale.
.NET Aspire è stato progettato fin dall’inizio per supportare lo sviluppo cloud native. Il suo modello permette di sviluppare applicazioni distribuite in locale, mantenendo una struttura già pronta per l’esecuzione in container o su servizi cloud gestiti.
Il vero valore sta nella separazione tra codice applicativo e infrastruttura: le risorse vengono scelte e configurate nell’AppHost, mentre i progetti continuano a funzionare allo stesso modo in ogni ambiente.
Nel prossimo articolo parleremo di osservabilità in .NET Aspire, approfondendo come log, metriche e tracing vengano raccolti automaticamente e resi disponibili nella dashboard.