Cuando Microsoft anunció .NET Aspire a finales de 2023, mi primera reacción fue escéptica. «Otro framework de orquestación», pensé. Me equivoqué bastante. Después de usarlo en proyectos reales —desde una API con tres microservicios hasta una arquitectura con colas, caché y modelos de IA local— cambió radicalmente cómo arranco proyectos distribuidos. En este artículo repaso qué es, cómo evolucionó de .NET 8 a .NET 10 y cómo puede convivir con tu stack de Kubernetes existente.
¿Qué es .NET Aspire y para quién está destinado?
.NET Aspire es un stack opinado (opinionated) de herramientas, plantillas y paquetes NuGet diseñado para construir aplicaciones distribuidas, observables y listas para producción con .NET. La palabra clave ahí es opinado: toma decisiones por vos (OpenTelemetry por defecto, health checks incluidos, service discovery automático) para que vos no tengas que hacerlo.
¿Para quién es?
- Equipos sin un DevOps dedicado: Facilita enormemente la orquestación local y el despliegue a la nube sin tener que escribir complejos archivos
docker-compose.ymlo manifiestos de K8s. - Desarrolladores que buscan productividad local: Permite levantar 5 microservicios, una base de datos PostgreSQL, un caché Redis y un broker RabbitMQ con un solo F5, autoconfigurando las cadenas de conexión y la inyección de dependencias entre ellos.
- Proyectos que requieren observabilidad inmediata: Trae un Dashboard local que muestra logs, métricas, trazas distribuidas (OpenTelemetry) y variables de entorno en tiempo real, sin necesidad de configurar Grafana, Prometheus o Jaeger localmente.
¿Para quién NO es (o no es obligatorio)?
Si sos un arquitecto que necesita control absoluto sobre el plano de red, service mesh y configuraciones avanzadas de orquestación, Aspire no tiene que reemplazar tu setup de producción. Pero sí puede ser tu entorno de desarrollo local mientras seguís gestionando todo con Helm y Kubernetes en prod. Más sobre esto al final.
Línea de Tiempo: De .NET 8 a .NET 10
El Origen: .NET 8 (Finales de 2023)
Nació como la respuesta de Microsoft a la complejidad de configurar microservicios localmente. Se introdujeron los conceptos de AppHost (el proyecto orquestador) y Service Defaults (configuraciones base de OpenTelemetry y resiliencia). En esta primera versión estaba bastante acoplado al ecosistema de Azure, lo que generó resistencia en quienes trabajaban con otros proveedores cloud. Aun así, la experiencia de desarrollo local era notablemente mejor que cualquier alternativa existente.
La Madurez: .NET 9 (Finales de 2024)
Aspire se desvinculó de ser «solo para Azure». La comunidad explotó: aparecieron decenas de integraciones para AWS, GCP y contenedores genéricos. El Dashboard mejoró considerablemente en rendimiento y se introdujo una gestión más robusta del ciclo de vida de los contenedores locales. Para este momento ya lo estaba usando en proyectos reales sin dudar.
El Estado Actual: .NET 10 (2025/2026)
Con .NET 10, Aspire se convirtió en el estándar de facto para arquitecturas distribuidas en .NET. Las novedades principales:
- Integración profunda con IA: Componentes nativos para orquestar contenedores de Ollama (modelos de IA locales), bases de datos vectoriales (Qdrant, Milvus) y configuración automática de Semantic Kernel.
- Event-Driven & Dapr: Integración fluida con arquitecturas dirigidas por eventos y soporte mejorado para Dapr.
- Manifiestos K8s Nativos: Mejoras en la exportación de la topología de Aspire hacia clústeres de Kubernetes, lo que facilita el trabajo de quienes administran sus propios servidores.
Conceptos Clave
AppHost: Tu docker-compose en C#
El AppHost es un proyecto de consola de C# normal que actúa como el orquestador local. En lugar de YAML, usás C# para definir qué contenedores o proyectos de .NET deben ejecutarse juntos. Si sabés C#, ya sabés escribir tu orquestación.
Service Discovery: Sin hardcodear puertos
Aspire inyecta automáticamente las URLs de los servicios. Si tu API «A» necesita llamar a la API «B», no hardcodeás localhost:5001. Aspire resuelve los nombres dinámicamente usando el nombre que vos le asignaste. Esto elimina una categoría entera de bugs que antes aparecían en desarrollo («funciona en mi máquina»).
Hosting & Client Integrations
Son paquetes NuGet que vienen en pares: uno para el AppHost que levanta el contenedor (Aspire.Hosting.Redis), y otro para el microservicio que lo consume (Aspire.StackExchange.Redis). Este segundo paquete configura automáticamente el cliente con resiliencia, health checks y telemetría. Sin boilerplate.
Ejemplos de Código (.NET 10)
A. El Orquestador: Proyecto AppHost
Este es el código que reemplaza a un docker-compose.yml. Cuando presionás F5 sobre este proyecto, Aspire levanta todos los contenedores, configura las variables de entorno y arranca los proyectos de .NET automáticamente.
var builder = DistributedApplication.CreateBuilder(args);
// 1. Contenedor de PostgreSQL con pgAdmin integrado
var postgres = builder.AddPostgres("postgres-server")
.WithPgAdmin()
.AddDatabase("MiBaseDeDatos");
// 2. Contenedor de Redis
var cache = builder.AddRedis("redis-cache");
// 3. Modelo de IA local con Ollama
var ollama = builder.AddOllama("ia-local")
.AddModel("llama3");
// 4. API Backend: recibe referencias a todos los recursos
var apiBackend = builder.AddProject<Projects.MiApiBackend>("backend-api")
.WithReference(postgres)
.WithReference(cache)
.WithReference(ollama);
// 5. Frontend Blazor: solo necesita saber dónde está la API
builder.AddProject<Projects.MiFrontendBlazor>("frontend-web")
.WithReference(apiBackend)
.WithExternalHttpEndpoints();
builder.Build().Run();
Lo que más me llamó la atención la primera vez: no hay ninguna cadena de conexión hardcodeada. Aspire las inyecta automáticamente en las variables de entorno de cada proyecto al momento de arrancar.
B. Consumiendo los recursos en la API
En el Program.cs de tu microservicio, usás las integraciones de Aspire. El nombre "redis-cache" o "MiBaseDeDatos" se resuelve automáticamente al contenedor correspondiente.
var builder = WebApplication.CreateBuilder(args);
// Configura OpenTelemetry, health checks y resiliencia por defecto
builder.AddServiceDefaults();
// Se conecta al Redis del AppHost por nombre, sin IP ni puerto
builder.AddRedisClient("redis-cache");
// Se conecta a Postgres, también por nombre
builder.AddNpgsqlDbContext<MiDbContext>("MiBaseDeDatos");
var app = builder.Build();
// Expone /health y /alive automáticamente
app.MapDefaultEndpoints();
app.MapGet("/datos", async (IDistributedCache cache, MiDbContext db) =>
{
// Usás los servicios como siempre, sin saber nada de cómo se conectaron
return Results.Ok(new { Mensaje = "Conectado por Aspire!" });
});
app.Run();
C. Service Discovery entre microservicios
En el Frontend, si queremos llamar al Backend por HTTP, usamos el nombre registrado en el AppHost. Aspire intercepta y resuelve el puerto real en tiempo de ejecución.
// En el Program.cs del Frontend Blazor
builder.Services.AddHttpClient<BackendClient>(client =>
{
// "backend-api" es el nombre del proyecto en el AppHost
// Aspire lo traduce al puerto correcto automáticamente
client.BaseAddress = new Uri("http://backend-api");
});
El primer día que esto funcionó sin tocar un solo archivo de configuración ni abrir el launchSettings.json, entendí por qué la gente dice que Aspire cambia la forma de trabajar.
¿Y si uso Kubernetes en producción?
Esta es la pregunta que más me hacen cuando presento Aspire. La respuesta corta: no son excluyentes.
Podés adoptar .NET Aspire únicamente como tu entorno de desarrollo local. Tus desarrolladores clonan el repositorio, presionan F5 y Aspire se encarga de levantar las bases de datos en Docker, configurar las variables de entorno y mostrar las trazas de OpenTelemetry en el Dashboard. Luego, en el pipeline de CI/CD, el proyecto AppHost simplemente se ignora: compilás tus contenedores como siempre y los desplegás en K8s con tus manifiestos o Helm Charts.
El resultado: productividad local extrema sin ceder ni un milímetro de control en producción. Para equipos que administran sus propios clústeres, es una combinación muy práctica.
Conclusión
.NET Aspire no es hype. Es una solución concreta a un problema real: configurar microservicios localmente es tedioso, propenso a errores y consume tiempo valioso de desarrollo. Con la evolución de .NET 8 a .NET 10 pasó de ser una herramienta interesante a ser el punto de partida obvio para cualquier arquitectura distribuida en .NET.
Si todavía no lo probaste, mi recomendación es crear un proyecto nuevo con la plantilla de Aspire, agregar un Redis y un Postgres, y ver el Dashboard en acción. En menos de 20 minutos vas a entender por qué está cambiando la forma en que trabajamos.
¿Lo estás usando en algún proyecto? ¿Tenés dudas sobre cómo integrarlo con tu setup actual? Dejalo en los comentarios.
Deja una respuesta