Aspire 13.2: Lo que los desarrolladores de servicios .NET necesitan saber
Compartiendo algunas notas sobre el lanzamiento de Aspire 13.2 del equipo de ingeniería aquí en Iron Software. Enviamos bibliotecas de .NET (IronPDF, IronOCR, IronXL, IronWord, IronBarcode, y el resto), y casi todas las llamadas de clientes terminan tocando la orquestación de aplicaciones distribuidas. Por eso prestamos atención a los lanzamientos de Aspire. 13.2 es el primero donde la CLI realmente se siente como si pudiera reemplazar el tablero de control para la mayor parte del trabajo diario, y hay algunos cambios rompientes que te afectarán en la actualización.
Esto no es una regurgitación de notas de lanzamiento. La página oficial de novedades tiene la lista exhaustiva. Esto es lo que es genuinamente útil en una base de código en funcionamiento, además de las advertencias a tener en cuenta.
En resumen
- La CLI ahora es genuinamente scriptable: modo separado,
aspire ps,aspire detener, modo aislado, salida JSON - TypeScript AppHost está en vista previa si quieres deshacerte del
.csprojpara la capa de orquestación - Archivos de configuración consolidados en
aspire.config.json(archivos heredados se migran automáticamente) - Foundry reemplaza a Azure AI Foundry. Este te romperá la construcción
WithSecretBuildArgse renombra aWithBuildSecret- Las vars de entorno de descubrimiento de servicio ahora usan esquema, no el nombre de punto final (riesgo de ruptura silenciosa)
- Comportamiento de credenciales predeterminado de Azure cambiado en integraciones de cliente
La CLI finalmente es una CLI
Esta es la cabecera. Antes de la versión 13.2, aspire run bloqueaba tu terminal y el dashboard era la única superficie realista para gestionar un apphost en ejecución. Bien para desarrolladores solitarios, incómodo para CI, pruebas de integración o cualquier flujo de trabajo impulsado por agentes.
13.2 soluciona esto:
# Run in the background
aspire run --detach
# Or the new shortcut
aspire start
# See what's running
aspire ps
# Stop it
aspire detener
aspire detener --all# Run in the background
aspire run --detach
# Or the new shortcut
aspire start
# See what's running
aspire ps
# Stop it
aspire detener
aspire detener --allCombinado con --format json (que va a stdout mientras que los mensajes de estado van a stderr, importante si estás canalizando a algún lugar), puedes construir una verdadera automatización en torno a esto. aspire ps --resources --format json es un sólido bloque de construcción para integraciones de editores y scripts.
El modo aislado es el héroe desconocido
--isolated es el que hemos estado esperando. Ejecuta un apphost con puertos aleatorios y secretos de usuario aislados, previniendo conflictos de puertos y colisiones de configuración:
aspire run --isolated
aspire start --isolatedaspire run --isolated
aspire start --isolatedSi alguna vez has intentado ejecutar dos revisiones del mismo apphost simultáneamente — digamos main contra una rama de características, pruebas de integración paralelas o flujos de trabajo impulsados por agentes — has sentido el dolor. Puertos aleatorios más secretos separados significa que finalmente puedes simplemente desplegar N copias y no preocuparte.
Para los arbolitos de trabajo de git por sí solos, vale la pena la actualización. Para los conjuntos de pruebas de integración que levantan servicios reales con dependencias nativas (renderizado de Chrome para generación de PDF, Tesseract para OCR, los habituales pesos pesados), es la diferencia entre ser inestable y ser fiable.
aspire doctor y aspire describe
aspire doctor recorre tu entorno: estado del certificado de desarrollo, versión del runtime de contenedores, SDK de .NET, configuración de WSL2, configuración de agentes. Es el tipo de cosa que cada framework debería tener y la mayoría no se molesta. La salida es accionable. Cuando algo está mal, te dice qué hacer.
aspire describe --follow te da una vista en streaming del estado de los recursos desde el terminal. Los mismos datos que muestra el tablero, pero canalizables. Pónlo en un panel de tmux y obtienes la mayor parte del valor del tablero en 80 columnas.
Los comandos de recursos se volvieron más ordenados
Los comandos antiguos resource-start / resource-detener / resource-restart están obsoletos en favor de la forma más limpia del subcomando:
aspire resource api restart
aspire resource api rebuildaspire resource api restart
aspire resource api rebuildrebuild es nuevo. Detiene, construye y reinicia un recurso de proyecto .NET único sin desmantelar toda la sesión de apphost. Si alguna vez has cambiado un servicio en un gráfico de 12 recursos y te has quejado de reiniciar todo, esta es la solución. Lo hemos sentido nosotros mismos: cuando estás iterando en una plantilla de renderizado de PDF o ajustando el preprocesamiento de OCR, reiniciar todo el gráfico solo para recargar un proyecto se vuelve viejo rápidamente.
Secretos y certificados sin salir de la CLI
Dos nuevos grupos de comandos dedicados:
aspire certs clean
aspire certs trust
aspire secret set ApiKey super-secret-value
aspire secret list --format jsonaspire certs clean
aspire certs trust
aspire secret set ApiKey super-secret-value
aspire secret list --format jsonaspire secret es la victoria más grande. Se mapea al mismo almacén de secretos de usuario que respalda AddParameter(..., secret: true) en el modelo de aplicación, pero no necesitas la CLI de .NET instalada para gestionarlos. En un apphost políglota donde no todos los desarrolladores tienen el SDK de .NET, esto importa.
aspire esperar por CI
aspire wait api --status healthy --timeout 120aspire wait api --status healthy --timeout 120Bloquearse en un estado de recurso. Combinado con aspire start y --format json, finalmente puedes escribir scripts de CI que esperan que las cosas realmente estén listas en lugar de sleep 30 && hope.
Configuración: un archivo para gobernarlos a todos
Aspire está consolidando sus archivos de configuración. La antigua división entre .aspire/settings.json y apphost.run.json ha desaparecido, reemplazada por un solo aspire.config.json en la raíz del proyecto:
{
"appHost": {
"path": "apphost.ts",
"language": "typescript/nodejs"
},
"sdk": { "version": "13.2.0" },
"channel": "stable",
"profiles": {
"default": {
"applicationUrl": "https://localhost:17000;http://localhost:15000"
}
}
}La migración es automática. La primera vez que ejecutes cualquier comando de aspire en un proyecto existente, los archivos heredados se fusionan en el nuevo formato con rutas reubicadas a la raíz del proyecto. Los archivos heredados se conservan, por lo que aún puedes usar versiones más antiguas de la CLI en paralelo. Las configuraciones globales (globalsettings.json) también se migran.
Si tienes automatización que interactúa directamente con .aspire/settings.json o apphost.run.json, planea moverla.
TypeScript AppHost (vista previa)
Esto es interesante incluso si no piensas usarlo desde el primer día. Ahora puedes escribir tu apphost en TypeScript en lugar de C#:
import { createBuilder } from './.modules/aspire.js';
const builder = await createBuilder();
const cache = await builder.addRedis("cache");
const api = await builder.addProject("api", "../api")
.withReference(cache)
.waitFor(cache);
await builder.build().run();Bajo el capó, el apphost de TS se ejecuta como un proceso invitado que se comunica con el anfitrión de orquestación .NET de Aspire a través de JSON-RPC en un transporte local. El mismo modelo de recursos, el mismo tablero, las mismas integraciones, solo que expresado en TypeScript.
La parte interesante es la generación de código. Cuando ejecutas aspire add, la CLI inspecciona el ensamblado de .NET de la integración y genera un SDK de TypeScript en .modules/. aspire restore los regenera, útil después de actualizar o cambiar de ramas (también se ejecuta automáticamente en aspire run). El generador 13.2 también añadió objetivos de prueba para Go, Java y Rust, lo que insinúa hacia dónde se dirige esto.
Para equipos prioritariamente .NET como el nuestro, esto es más "observar esto" que "enviar esto", pero el patrón de generación de código significa que los futuros lenguajes de apphost políglotas siguen el mismo modelo. Consulten los documentos de arquitectura de múltiples lenguajes para ver cómo funciona el puente del anfitrión.
Tablero: la exportación/importación de telemetría es el nuevo juguete
El tablero obtuvo un flujo de trabajo real de exportación/importación. Desde Configuración → Gestión, elige recursos y tipos de telemetría y expórtalos como JSON en un zip. Reimporta en el tablero después, o pásaselo a otra persona (o un LLM) para su análisis.
El comando de la CLI aspire export produce el mismo paquete:
aspire export --output .\artifacts\aspire-export.zip
aspire export <resource>aspire export --output .\artifacts\aspire-export.zip
aspire export <resource>Verdaderamente útil para informes de errores. En lugar de "aquí hay algunas capturas de pantalla y un archivo de registro", puedes adjuntar una instantánea del estado real de la telemetría.
Otras notas desde el lado del panel:
- Ahora puedes establecer parámetros de recursos directamente desde la interfaz del panel, con una opción para persistir en secretos de usuario
- Las variables de entorno se pueden exportar como archivos
.envdesde la vista de detalles de recursos - El diseño del gráfico de recursos utiliza posicionamiento por fuerzas adaptativas. Los gráficos complejos son notablemente menos desordenados
- API HTTP de telemetría en
/api/telemetrydevuelve JSON OTLP; soporta?follow=truepara streaming NDJSON. Los puntos finales cubren recursos, spans, logs y trazas (incluyendo/traces/{traceId}para búsqueda completa de trazas)
El panel independiente ahora configura la API de telemetría como desactivada por defecto. Si estás alojando el dashboard tú mismo y dependiendo de la API, necesitas DASHBOARD__API__ENABLED=true más la configuración de autenticación (DASHBOARD__API__AUTHMODE y DASHBOARD__API__PRIMARYAPIKEY). Los escenarios integrados de AppHost aún funcionan porque Aspire.Hosting conecta automáticamente la API para las herramientas.
Aspectos del modelo de aplicación que vale la pena notar
WithMcpServer
Puedes declarar en el modelo de aplicación que un recurso alberga un punto final MCP:
var api = builder.AddProject<Projects.MyApi>("api")
.WithMcpServer("/mcp");var api = builder.AddProject<Projects.MyApi>("api")
.WithMcpServer("/mcp");Dim api = builder.AddProject(Of Projects.MyApi)("api") _
.WithMcpServer("/mcp")Las herramientas Aspire pueden entonces descubrir y proxificar ese punto final. Si estás distribuyendo algo que expone herramientas a agentes de codificación, esta es la forma más limpia de conectarlo. Ruta personalizada o nombre de punto final soportados a través de opciones.
Resolución de puntos finales contextuales
Este es el tipo de cosas que no notarás hasta que lo necesites. Ahora los puntos finales pueden resolverse desde la perspectiva de un llamante específico o red:
var endpoint = redis.GetEndpoint("tcp");
var url = await endpoint.GetValueAsync(new ValueProviderContext {
Caller = containerApp.Resource,
});var endpoint = redis.GetEndpoint("tcp");
var url = await endpoint.GetValueAsync(new ValueProviderContext {
Caller = containerApp.Resource,
});Dim endpoint = redis.GetEndpoint("tcp")
Dim url = Await endpoint.GetValueAsync(New ValueProviderContext With {
.Caller = containerApp.Resource
})El mismo endpoint de Redis se resolverá a localhost:6379 desde un proceso host, host.docker.internal:6379 desde un contenedor en la red del host, o cache:6379 desde un contenedor en la red de Aspire, dependiendo del contexto. La clase KnownNetworkIdentifiers te da LocalhostNetwork, DefaultAspireContainerNetwork, y PublicInternet si prefieres elegir una red en lugar de un llamador.
Las notas de la versión llaman explícitamente la atención sobre que estas API existían en la 13.1 pero no se comportaban correctamente. Así que si escribiste algo contra ellas en la 13.1, vuelve a realizar pruebas. Detalles completos en los documentos de jerarquías de recursos.
Secretos de construcción de contenedores
WithSecretBuildArg se renombra a WithBuildSecret. El nuevo nombre es más claro. Estos fluyen a través de Docker/Podman como verdaderos secretos de construcción, no como argumentos de construcción (que se filtran en el historial de la imagen).
builder.AddContainer("worker", "contoso/worker")
.WithDockerfile("../worker")
.WithBuildSecret("ACCESS_TOKEN", accessToken);builder.AddContainer("worker", "contoso/worker")
.WithDockerfile("../worker")
.WithBuildSecret("ACCESS_TOKEN", accessToken);Los secretos de compilación ahora también pueden ser archivos (por ejemplo, .npmrc para autenticación de registro privado en construcciones de contenedores), lo que cubre la mayoría de los casos de uso en el mundo real.
Integraciones: las que importan
La lista completa es larga. Estas son las que destacaría:
- La publicación de Docker Compose ahora es estable (era pre-lanzamiento).
AddDockerComposeEnvironmentgenera undocker-compose.yamldesde tu modelo de aplicación al momento de la publicación. Salida útil cuando 'desplegar en Azure' no es la respuesta. Vale la pena destacarlo si estás distribuyendo contenedores que incluyen dependencias nativas, ya que IronPDF, IronOCR y IronXL soportan contenedores Linux y Docker de manera limpia, por lo que el archivo compose generado usualmente funciona sin intervención manual. - La integración de Azure Virtual Network (
Aspire.Hosting.Azure.Network) te permite declarar VNets, subredes, NSGs, gateways NAT, y endpoints privados en el apphost.AddPrivateEndpointcrea automáticamente zonas de DNS privadas, enlaces de redes virtuales, y desactiva el acceso público en el objetivo. Este es el tipo de cosas que anteriormente significaba mantener un archivo Bicep separado. - Azure Data Lake Storage obtuvo soporte tanto de hosting como de cliente:
AddDataLake,AddDataLakeFileSystem, másAddAzureDataLakeServiceClient/AddAzureDataLakeFileSystemClientdel lado del cliente. Registro DI, reintentos, verificaciones de salud, telemetría, lo usual en la pila de Aspire. - MongoDB EF Core tiene una nueva integración de cliente (
Aspire.MongoDB.EntityFrameworkCore).AddMongoDbContext<TContext>para el caso típico, oEnrichMongoDbContext<TContext>()si estás registrando el DbContext tú mismo. - Azure AI Inference ahora soporta incrustaciones, no solo chat. Registra
AddAzureEmbeddingsClient("embeddings").AddEmbeddingGenerator()e inyectaIEmbeddingGenerator<string, Embedding<float>>. Variante clave también disponible. - El Azure Container Registry obtuvo
WithPurgeTask("0 1 * * *", ago: TimeSpan.FromDays(7), keep: 5), que provisiona una tarea de purga de ACR en un cronograma. - Soporte para Bun para recursos JavaScript a través de
WithBun(). La fiabilidad de Yarn conAddViteApptambién se solucionó a través deWithYarn(). - Microsoft Foundry reemplaza Azure AI Foundry.
Aspire.Hosting.Foundryreemplaza aAspire.Hosting.Azure.AIFoundry. Cambio radical; detalles abajo.
Poniéndolo todo junto: un servicio de documentos en Aspire 13.2
Aquí está el patrón que usamos internamente para probar escenarios distribuidos con nuestras bibliotecas. Vale la pena mostrarlo porque la mayoría de las nuevas características de la 13.2 rinden frutos en esta configuración de múltiples servicios, no en demos juguete.
var builder = DistributedApplication.CreateBuilder(args);
var cache = builder.AddRedis("cache");
// A worker service that uses IronPDF for HTML to PDF rendering
var renderer = builder.AddProject<Projects.PdfRenderer>("renderer")
.WithReference(cache)
.WaitFor(cache)
.WithMcpServer("/mcp");
// An OCR worker that uses IronOCR for image and PDF text extraction
var ocr = builder.AddProject<Projects.OcrWorker>("ocr-worker")
.WithReference(cache);
// API gateway that fans out to both
builder.AddProject<Projects.Api>("api")
.WithReference(renderer)
.WithReference(ocr)
.WaitFor(renderer)
.WaitFor(ocr);
builder.Build().Run();var builder = DistributedApplication.CreateBuilder(args);
var cache = builder.AddRedis("cache");
// A worker service that uses IronPDF for HTML to PDF rendering
var renderer = builder.AddProject<Projects.PdfRenderer>("renderer")
.WithReference(cache)
.WaitFor(cache)
.WithMcpServer("/mcp");
// An OCR worker that uses IronOCR for image and PDF text extraction
var ocr = builder.AddProject<Projects.OcrWorker>("ocr-worker")
.WithReference(cache);
// API gateway that fans out to both
builder.AddProject<Projects.Api>("api")
.WithReference(renderer)
.WithReference(ocr)
.WaitFor(renderer)
.WaitFor(ocr);
builder.Build().Run();Imports DistributedApplication
Dim builder = DistributedApplication.CreateBuilder(args)
Dim cache = builder.AddRedis("cache")
' A worker service that uses IronPDF for HTML to PDF rendering
Dim renderer = builder.AddProject(Of Projects.PdfRenderer)("renderer") _
.WithReference(cache) _
.WaitFor(cache) _
.WithMcpServer("/mcp")
' An OCR worker that uses IronOCR for image and PDF text extraction
Dim ocr = builder.AddProject(Of Projects.OcrWorker)("ocr-worker") _
.WithReference(cache)
' API gateway that fans out to both
builder.AddProject(Of Projects.Api)("api") _
.WithReference(renderer) _
.WithReference(ocr) _
.WaitFor(renderer) _
.WaitFor(ocr)
builder.Build().Run()Lo que obtienes específicamente de la 13.2:
aspire start --isolatedte permite ejecutar dos copias de este gráfico lado a lado sin colisiones de puertos. Útil al comparar ramas o realizar pruebas de integración paralelas contra el renderizadoraspire resource renderer rebuildrecarga solo el renderizador PDF cuando cambias una plantilla Razor, en lugar de rebotear todo el gráficoaspire wait renderer --status healthy --timeout 120permite que tu CI se bloquee hasta que se inicialice la renderización en Chrome antes de ejecutar pruebas de generación de PDF- La API HTTP de telemetría y
aspire exportte dan spans en formato OTLP para cada llamada de renderizado, lo cual es cómo capturas una regla CSS lenta en tráfico de producción WithMcpServerte permite exponer el renderizador como una herramienta MCP para flujos de trabajo de agentes de codificación, útil si estás construyendo algo que genera documentos programáticamente
Si deseas construir un servicio como el renderizador anterior, el tutorial de HTML a PDF de IronPDF recorre el lado de C#. Para el trabajador OCR, la guía de inicio de IronOCR cubre lo básico.
Cambios radicales que realmente te afectarán
En un orden aproximado de qué tan probable es que te afecten:
Descubrimiento de servicio renombramiento de vars de entorno
# Before (13.0/13.1)
services__myservice__myendpoint__0 = https://localhost:5001
# After (13.2)
services__myservice__https__0 = https://localhost:5001# Before (13.0/13.1)
services__myservice__myendpoint__0 = https://localhost:5001
# After (13.2)
services__myservice__https__0 = https://localhost:5001Se usa el esquema del punto final en lugar del nombre del punto final. Si tienes algún código o configuración que coincide con esos nombres de variables de entorno, actualízalo. Este es el corte silencioso más probable: nada lanza una excepción, las variables simplemente tienen diferentes claves.
BeforeResourceStartedEvent
Anteriormente disparado más ampliamente; ahora solo se activa al iniciar realmente un recurso, no en cada cambio de estado. Si tu controlador contaba con el comportamiento anterior, dejará de ejecutarse silenciosamente.
AIFoundry a Foundry
Renombrar paquete y API. Actualiza la referencia del paquete y las llamadas:
<PackageReference Include="Aspire.Hosting.Foundry" Version="13.2.0" /><PackageReference Include="Aspire.Hosting.Foundry" Version="13.2.0" />// Before
var ai = builder.AddAzureAIFoundry("ai");
// After
var foundry = builder.AddFoundry("ai");
var project = foundry.AddProject("agents");
var chat = project.AddModelDeployment("chat", FoundryModel.OpenAI.Gpt5Mini);// Before
var ai = builder.AddAzureAIFoundry("ai");
// After
var foundry = builder.AddFoundry("ai");
var project = foundry.AddProject("agents");
var chat = project.AddModelDeployment("chat", FoundryModel.OpenAI.Gpt5Mini);' Before
Dim ai = builder.AddAzureAIFoundry("ai")
' After
Dim foundry = builder.AddFoundry("ai")
Dim project = foundry.AddProject("agents")
Dim chat = project.AddModelDeployment("chat", FoundryModel.OpenAI.Gpt5Mini)RunAsFoundryLocal todavía funciona para desarrollo de modelos locales, pero los Proyectos Foundry no son compatibles cuando el recurso padre está configurado como Foundry Local.
Credencial predeterminada de Azure
Las integraciones del cliente de Aspire Azure ya no usan el constructor DefaultAzureCredential sin parámetros. Si estabas confiando en credenciales diferentes a ManagedIdentityCredential trabajando en un servicio de Azure, el comportamiento cambia. Lee el documento de credencial predeterminada de Azure antes de actualizar la producción.
Renombramiento de comando de recurso
resource-start / resource-detener / resource-restart ahora son aspire resource <name> start|detener|reiniciar. Actualiza cualquier script. La opción--apphosttambién ahora es preferida sobre la heredada--project` (que aún es aceptada).
Sufijo de propiedad de conexión
Se añadió un sufijo de propiedad de conexión. Si accedes a las propiedades de conexión directamente (en lugar de a través de WithReference), verifica que tu código aún las resuelva.
WithSecretBuildArg a WithBuildSecret
Mencionado arriba. Renombramiento directo.
IAzureContainerRegistry obsoleto
Usa la propiedad ContainerRegistry en entornos de computación en su lugar.
API de telemetría del panel ahora optativa (independiente)
Ya cubierto arriba, pero vale la pena repetirlo: las implementaciones independientes del panel necesitan habilitar explícitamente la API ahora.
¿Deberías actualizar?
Para una tienda trabajando con .NET que ejecuta aplicaciones multi-servicio localmente, sí, asumiendo que has inventariado los cambios radicales anteriores. Las mejoras a la CLI por sí solas valen la pena. El modo desacoplado y el modo aislado en particular resuelven problemas reales de flujo de trabajo.
Para usuarios de Foundry: el renombramiento es una migración forzada si deseas algo nuevo de esta versión, así que planifica en consecuencia.
Para las personas curiosas de TypeScript: 13.2 es la primera versión en la que el apphost TS es lo suficientemente real como para evaluar. Todavía en vista previa, pero vale la pena un viernes por la tarde.
La actualización en sí es una línea si ya estás en 13.x:
aspire update --self
aspire updateaspire update --self
aspire updateSi estás en 12.x o anterior, primero lee la guía de actualización. Hay un paso de 13.0 que no puedes omitir.
Nota de parche: 13.2.1
13.2.1 ha sido enviado desde el lanzamiento original con correcciones de confiabilidad. Hay un pequeño renombramiento del SDK TypeScript que vale la pena notar, solo importa si ya estás en la vista previa del apphost TS:
| Anterior | Nuevo |
|---|---|
runAsExistingFromParameters(name, resourceGroup) | runAsExisting(name, { resourceGroup }) |
publishAsExistingFromParameters(name, resourceGroup) | publishAsExisting(name, { resourceGroup }) |
withConnectionPropertyValue(name, value) | withConnectionProperty(name, value) |
withParameterBuildArg(name, parameter) | withBuildArg(name, parameter) |
withConnectionPropertyValue se mantiene como un alias de compatibilidad en los SDKs generados, por lo que no es una ruptura en tiempo de ejecución.
¿Construyendo aplicaciones .NET distribuidas con cargas de trabajo de documentos?
Si tus servicios generan PDF, OCR, procesan Excel, códigos de barras o cualquier otro formato que cubrimos, nuestras bibliotecas están diseñadas para este tipo de configuración multi-servicio y amigable con contenedores que Aspire orquesta. Todo soporta .NET 10, 9, 8, 7, 6, Framework y Core, y se ejecuta en contenedores Linux, Azure, AWS y en premisas.
Algunos lugares para comenzar:
- IronPDF para HTML a PDF, edición de PDF, firma y formularios. El centro de tutoriales es el camino más rápido para un servicio de renderizado funcional
- IronOCR para extracción de texto de imágenes y PDF en más de 125 idiomas
- IronXL para lectura/escritura de Excel sin Interop de Office
- IronWord para generación y edición de DOCX
- IronBarcode y IronQR para generación y escaneo de códigos de barras y QR
- Iron Suite si necesitas más de uno de los anteriores
Puedes obtener una clave de prueba de 30 días y tener un servicio funcional de PDF u OCR corriendo dentro de un aspire apphost en menos de una hora. Si encuentras algo raro, nuestro equipo de soporte son ingenieros reales, no una cola de clasificación de tickets.
Eso es todo. Nos vemos en la próxima versión.
