Build 2025: Perspectivas de IA e .NET para clientes da Iron Software
Compartilhando algumas notas sobre o lançamento do Aspire 13.2 da equipe de engenharia aqui na Iron Software. Enviamos bibliotecas .NET (IronPDF, IronOCR, IronXL, IronWord, IronBarcode, e o resto), e praticamente todas as chamadas de clientes tocam em orquestração de aplicativos distribuídos. É por isso que prestamos atenção às versões Aspire. 13.2 é o primeiro onde o CLI parece que pode realmente substituir o painel para a maior parte do trabalho diário, e há algumas mudanças significativas que vão afetá-lo na atualização.
Este não é um regurgito de notas de lançamento. A página oficial de novidades tem a lista completa. Isto é o que é genuinamente útil em uma base de código de trabalho, além das armadilhas para observar.
Resumindo
- A CLI agora é genuinamente scriptável: modo desacoplado,
aspire ps,aspire stop, modo isolado, saída em JSON - TypeScript AppHost está em pré-visualização se você quiser abandonar o
.csprojpara a camada de orquestração - Arquivos de configuração consolidados em
aspire.config.json(arquivos legados migram automaticamente) - Foundry substitui Azure AI Foundry. Este vai quebrar sua build
WithSecretBuildArgfoi renomeado paraWithBuildSecret- Env vars de descoberta de serviço agora usam esquema, não o nome do endpoint (risco de quebra silenciosa)
- Comportamento padrão de credenciais Azure alterado em integrações de cliente
O CLI finalmente é um CLI
Este é o título. Antes da versão 13.2, aspire run bloqueava seu terminal e o dashboard era a única superfície realista para gerenciar um apphost em execução. Bom para desenvolvedores solo, complicado para CI, testes de integração ou qualquer fluxo de trabalho guiado por agentes.
13.2 corrige isso:
# Run in the background
aspire run --detach
# Or the new shortcut
aspire start
# See what's running
aspire ps
# Stop it
aspire stop
aspire stop --all
# Run in the background
aspire run --detach
# Or the new shortcut
aspire start
# See what's running
aspire ps
# Stop it
aspire stop
aspire stop --all
Combinado com --format json (que vai para o stdout enquanto mensagens de status vão para o stderr, importante se você estiver encaminhando para algum lugar), você pode construir automação real em torno disso. aspire ps --resources --format json é um bloco de construção sólido para integrações de editores e scripts.
O modo isolado é o herói desconhecido
--isolated é o que estávamos esperando. Ele executa um apphost com portas randomizadas e segredos de usuário isolados, prevenindo conflitos de porta e colisões de configuração:
aspire run --isolated
aspire start --isolated
aspire run --isolated
aspire start --isolated
Se você já tentou executar dois checkouts do mesmo apphost simultaneamente — digamos, principal contra um branch de recurso, testes de integração paralelos ou fluxos de trabalho dirigidos por agente — você já sentiu a dor. Portas aleatórias mais segredos separados significam que você pode finalmente apenas iniciar N cópias e não se preocupar.
Somente para worktrees do git, isso já vale o upgrade. Para suítes de testes de integração que trazem serviços reais com dependências nativas (renderização no Chrome para geração de PDF, Tesseract para OCR, os pesos pesados usuais), é a diferença entre instável e confiável.
aspire doctor e aspire describe
aspire doctor executa através do seu ambiente: estado do certificado de desenvolvimento, versão do tempo de execução do contêiner, SDK do .NET, configuração do WSL2, configuração do agente. É o tipo de coisa que todo framework deveria ter e a maioria não se incomoda. A saída é aplicável. Quando algo está errado, ele diz o que fazer.
aspire describe --follow oferece uma visão contínua do estado do recurso a partir do terminal. Os mesmos dados que o painel exibe, mas canalizáveis. Coloque-o em um painel tmux e você obtém a maior parte do valor do painel em 80 colunas.
Os comandos de recurso ficaram mais organizados
Os antigos comandos resource-start / resource-stop / resource-restart são desaprovados em favor de uma forma de subcomando mais limpa:
aspire resource api restart
aspire resource api rebuild
aspire resource api restart
aspire resource api rebuild
rebuild é novo. Ele para, compila e reinicia um único recurso de projeto .NET sem desmontar toda a sessão do apphost. Se você já alterou um serviço em um gráfico de 12 recursos e resmungou ao reiniciar tudo, esta é a solução. Sentimos isso nós mesmos: quando você está iterando em um modelo de renderização de PDF ou ajustando o pré-processamento OCR, reiniciar todo o gráfico apenas para recarregar um projeto fica velho rapidamente.
Segredos e certificados sem sair da CLI
Dois novos grupos de comando dedicados:
aspire certs clean
aspire certs trust
aspire secret set ApiKey super-secret-value
aspire secret list --format json
aspire certs clean
aspire certs trust
aspire secret set ApiKey super-secret-value
aspire secret list --format json
aspire secret é o maior ganho. Ele mapeia para o mesmo armazenamento de segredos de usuário que suporta AddParameter(..., secret: true) no modelo de aplicativo, mas você não precisa ter o CLI do .NET instalado para gerenciá-los. Em um apphost poliglota onde nem todo desenvolvedor tem o SDK .NET, isso é importante.
aspire, aguarde pelo CI
aspire wait api --status healthy --timeout 120
aspire wait api --status healthy --timeout 120
Bloqueie no estado de um recurso. Combinado com aspire start e --format json, você pode finalmente escrever scripts de CI que aguardam até que as coisas realmente estejam prontas, em vez de sleep 30 && hope.
Configuração: um arquivo para governar todos
Aspire está consolidando seus arquivos de configuração. A antiga divisão entre .aspire/settings.json e apphost.run.json desapareceu, sendo substituída por um único aspire.config.json na raiz do projeto:
{
"appHost": {
"path": "apphost.ts",
"language": "typescript/nodejs"
},
"sdk": { "version": "13.2.0" },
"channel": "stable",
"profiles": {
"default": {
"applicationUrl": "https://localhost:17000;http://localhost:15000"
}
}
}
A migração é automática. Na primeira vez que você executar qualquer comando aspire em um projeto existente, os arquivos legados são mesclados no novo formato com os caminhos rebaseados para a raiz do projeto. Arquivos legados são preservados para que você ainda possa usar versões antigas do CLI lado a lado. Configurações globais (globalsettings.json) também são migradas.
Se você tem automação que acessa diretamente .aspire/settings.json ou apphost.run.json, planeje mover isso.
TypeScript AppHost (prévia)
Isso é interessante mesmo que você não vá usar no primeiro dia. Agora você pode escrever seu apphost em TypeScript em vez 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();
Nos bastidores, o apphost TS executa como um processo convidado conversando com o host de orquestração .NET do Aspire sobre JSON-RPC em um transporte local. Mesmo modelo de recurso, mesmo painel, mesmas integrações, apenas expresso em TypeScript.
A parte interessante é o codegen. Quando você executa aspire add, o CLI inspeciona a montagem .NET da integração e gera um SDK TypeScript em .modules/. aspire restore os regenera, útil após atualizar ou mudar de branch (também é executado automaticamente em aspire run). O gerador 13.2 também adicionou alvos de teste Go, Java e Rust, o que sugere onde isso está indo.
Para equipes que priorizam .NET como a nossa, isso é mais "assista isso" do que "envie isso", mas o padrão de codegen significa que futuras linguagens de apphost poliglota seguirão o mesmo modelo. Veja a documentação de arquitetura multi-linguagem para saber como a ponte do host funciona.
Painel: exportação/importação de telemetria é o novo brinquedo
O painel ganhou um fluxo real de trabalho de exportação/importação. Em Configurações → Gerenciar, escolha recursos e tipos de telemetria e exporte-os como JSON em um zip. Reimporte no painel mais tarde, ou passe para outra pessoa (ou um LLM) para análise.
O comando CLI aspire export produz o mesmo pacote:
aspire export --output .\artifacts\aspire-export.zip
aspire export <resource>
aspire export --output .\artifacts\aspire-export.zip
aspire export <resource>
Genuinamente útil para relatórios de bugs. Em vez de "aqui estão algumas capturas de tela e um arquivo de log", você pode anexar uma foto instantânea do estado real da telemetria.
Outras notas do lado do painel:
- Agora você pode definir parâmetros de recurso diretamente da interface do painel, com uma opção para persistir nos segredos do usuário
- Variáveis de ambiente podem ser exportadas como arquivos
.enva partir da visualização de detalhes do recurso - O layout do gráfico de recursos usa posicionamento adaptável baseado em forças. Gráficos complexos estão notavelmente menos desordenados
- API HTTP de telemetria em
/api/telemetryretorna JSON OTLP; suporta?follow=truepara transmissão de NDJSON. Os endpoints cobrem recursos, spans, logs e traces (incluindo/traces/{traceId}para consulta completa de trace)
O painel independente agora define a API de telemetria como desativada por padrão. Se você estiver hospedando o dashboard por conta própria e dependendo da API, precisará de DASHBOARD__API__ENABLED=true mais configuração de autenticação (DASHBOARD__API__AUTHMODE e DASHBOARD__API__PRIMARYAPIKEY). Cenários integrados ao AppHost ainda funcionam porque Aspire.Hosting conecta automaticamente a API para ferramentas.
Fragmentos do modelo de aplicativo que valem a pena notar
WithMcpServer
Você pode declarar no modelo de aplicativo que um recurso hospeda um endpoint 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")
Ferramentas do Aspire podem então descobrir e proxy esse endpoint. Se você está distribuindo qualquer coisa que exponha ferramentas para agentes de codificação, esta é a maneira mais limpa de integrá-lo. Caminho ou nome de endpoint personalizado suportado através de opções.
Resolução de endpoint contextual
Este é o tipo de coisa que você não percebe até precisar. Agora, os endpoints podem ser resolvidos na perspectiva de um chamador ou rede específico:
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
})
O mesmo endpoint Redis irá resolver para localhost:6379 a partir de um processo host, host.docker.internal:6379 a partir de um contêiner na rede do host, ou cache:6379 a partir de um contêiner na rede de contêineres Aspire, dependendo do contexto. A classe KnownNetworkIdentifiers fornece LocalhostNetwork, DefaultAspireContainerNetwork, e PublicInternet se preferir escolher uma rede em vez de um chamador.
As notas de lançamento chamam explicitamente a atenção para o fato de que essas APIs existiam no 13.1, mas não se comportavam corretamente. Portanto, se você escreveu algo contra elas no 13.1, reteste. Detalhes completos na documentação de hierarquias de recursos.
Segredos de compilação de container
WithSecretBuildArg foi renomeado para WithBuildSecret. O novo nome é mais claro. Estes fluem através do Docker/Podman como segredos de compilação adequados, não como argumentos de compilação (que vazam para o histórico da imagem).
builder.AddContainer("worker", "contoso/worker")
.WithDockerfile("../worker")
.WithBuildSecret("ACCESS_TOKEN", accessToken);
builder.AddContainer("worker", "contoso/worker")
.WithDockerfile("../worker")
.WithBuildSecret("ACCESS_TOKEN", accessToken);
Segredos de construção agora também podem ser arquivos (por exemplo, .npmrc para autenticação de registro privado em construções de contêineres), o que cobre a maioria dos casos de uso no mundo real.
Integrações: as que importam
A lista completa é longa. Estas são as que eu destacaria:
- A publicação do Docker Compose agora é estável (era pré-lançamento).
AddDockerComposeEnvironmentgera umdocker-compose.yamldo seu modelo de aplicativo no momento da publicação. Saída útil quando "implantar no Azure" não é a resposta. Vale a pena notar se você estiver distribuindo contêineres que incluem dependências nativas, já que IronPDF, IronOCR e IronXL suportam contêineres Linux e Docker de forma limpa, então o arquivo de composição gerado geralmente funciona sem cirurgia manual. - Integração Rede Virtual do Azure (
Aspire.Hosting.Azure.Network) permite declarar VNets, sub-redes, NSGs, gateways NAT e endpoints privados no apphost.AddPrivateEndpointcria automaticamente zonas DNS privadas, links de rede virtual e desabilita o acesso público no destino. Este é o tipo de coisa que anteriormente significava manter um arquivo Bicep separado. - Armazenamento de Data Lake do Azure recebeu suporte tanto para hospedagem quanto para cliente:
AddDataLake,AddDataLakeFileSystem, maisAddAzureDataLakeServiceClient/AddAzureDataLakeFileSystemClientdo lado do cliente. Registro DI, tentativas, verificações de saúde, telemetria, a pilha Aspire usual. - MongoDB EF Core tem uma nova integração de cliente (
Aspire.MongoDB.EntityFrameworkCore).AddMongoDbContext<TContext>para o caso típico, ouEnrichMongoDbContext<TContext>()se você estiver registrando o DbContext por conta própria. - Inferência Azure AI agora oferece suporte a embeddings, não apenas chat. Registre
AddAzureEmbeddingsClient("embeddings").AddEmbeddingGenerator()e injeteIEmbeddingGenerator<string, Embedding<float>>. Variante chaveada disponível também. - Azure Container Registry conseguiu
WithPurgeTask("0 1 * * *", ago: TimeSpan.FromDays(7), keep: 5), que provisiona uma tarefa de limpeza de ACR em um cronograma. - Suporte ao Bun para recursos JavaScript via
WithBun(). Confiabilidade do Yarn comAddViteApptambém foi corrigida viaWithYarn(). - Microsoft Foundry substitui Azure AI Foundry.
Aspire.Hosting.FoundrysubstituiAspire.Hosting.Azure.AIFoundry. Mudança disruptiva; detalhes abaixo.
Juntando tudo: um serviço de documentos no Aspire 13.2
Este é o padrão que usamos internamente para testar cenários distribuídos com nossas bibliotecas. Vale a pena mostrar porque a maioria dos novos recursos 13.2 compensa neste tipo de configuração de multi-serviço, não em demos brinquedo.
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()
O que você obtém especificamente do 13.2:
aspire start --isolatedpermite que você execute duas cópias deste gráfico lado a lado sem colisões de porta. Útil ao comparar branches ou executar testes de integração paralelos contra o renderizadoraspire resource renderer rebuildrecarrega apenas o renderizador de PDF quando você altera um modelo Razor, em vez de reiniciar todo o gráficoaspire wait renderer --status healthy --timeout 120permite que seu CI bloqueie até que o renderizador Chrome seja inicializado antes de executar testes de geração de PDF- A API HTTP de telemetria e
aspire exportlhe dão spans formatados em OTLP para cada chamada de renderização, que é como você realmente pegaria uma regra CSS lenta em tráfego de produção WithMcpServerpermite que você exponha o renderizador como uma ferramenta MCP para fluxos de trabalho de agentes de codificação, útil se você estiver construindo qualquer coisa que gere documentos programaticamente
Se você quiser construir um serviço como o renderizador acima, o tutorial HTML para PDF do IronPDF explica o lado do C#. Para o trabalhador OCR, o guia de introdução do IronOCR cobre o básico.
Mudanças disruptivas que realmente te morderão
Em ordem aproximada de quão provável você é de encontrá-los:
Nomenclatura de env var de descoberta de serviço
# 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:5001
O esquema do endpoint é usado em vez do nome do endpoint. Se você tem qualquer código ou configuração que corresponda a esses nomes de env var, atualize-os. Este é o erro silencioso mais provável: nada é lançado, as variáveis apenas têm diferentes chaves.
BeforeResourceStartedEvent
Anteriormente disparado mais amplamente; agora só dispara quando realmente inicia um recurso, não em cada mudança de estado. Se o seu manipulador contava com o comportamento anterior, ele silenciosamente deixará de ser executado.
AIFoundry para Foundry
Renomeação de pacote e API. Atualize a referência de pacote e as chamadas:
<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 ainda funciona para desenvolvimento de modelos locais, mas Projetos Foundry não são suportados quando o recurso principal está configurado como Foundry Local.
Credencial padrão do Azure
Integrações de clientes Aspire Azure não usam mais o construtor DefaultAzureCredential sem parâmetros. Se você estava confiando em credenciais diferentes de ManagedIdentityCredential funcionando em um serviço do Azure, o comportamento muda. Leia o documento de credencial padrão do Azure antes de atualizar a produção.
Renomeação de comando de recurso
resource-start / resource-stop / resource-restart are now aspire resource <name> start|stop|reiniciar. Atualize qualquer script. A opção --apphost também é agora preferida sobre o legado --project (que ainda é aceito).
Sufixo de propriedade de conexão
Um sufixo de propriedade de conexão foi adicionado. Se você acessar propriedades de conexão diretamente (em vez de via WithReference), verifique se seu código ainda as resolve.
WithSecretBuildArg para WithBuildSecret
Mencionado acima. Renomeação direta.
IAzureContainerRegistry obsoleto
Use a propriedade ContainerRegistry em ambientes de computação em vez disso.
API de telemetria de painel agora com opção para entrar (independente)
Já abordado acima, mas vale a pena repetir: implantações de painel independentes agora precisam habilitar a API explicitamente.
Você deve atualizar?
Para uma loja .NET funcional rodando apps de multi-serviços localmente, sim, assumindo que você inventariou as mudanças críticas acima. As melhorias no CLI por si só valem a pena. Os modos destacado e isolado, em particular, resolvem problemas reais de fluxo de trabalho.
Para usuários do Foundry: a renomeação é uma migração forçada se você quiser qualquer novidade desta versão, portanto, planeje de acordo.
Para os curiosos sobre TypeScript: 13.2 é a primeira versão em que o apphost TS é real o suficiente para ser avaliado. Ainda em pré-visualização, mas vale uma tarde de sexta-feira.
A atualização em si é uma linha se você já estiver no 13.x:
aspire update --self
aspire update
aspire update --self
aspire update
Se você estiver no 12.x ou anterior, acesse primeiro o guia de atualização. Há um passo no 13.0 que você não pode pular.
Notas de patch: 13.2.1
13.2.1 foi enviada desde a versão original com correções de confiabilidade. Há uma pequena renomeação no SDK TypeScript que vale a pena mencionar, só importa se você já estiver na pré-visualização do apphost TS:
| Anterior | Novo |
|---|---|
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 é mantido como um alias de compatibilidade nos SDKs gerados, então não é uma quebra de tempo de execução.
Construindo apps .NET distribuídos com cargas de trabalho de documentos?
Se os seus serviços realizam geração de PDF, OCR, processamento de Excel, códigos de barras ou quaisquer outros formatos que cobrimos, nossas bibliotecas são projetadas exatamente para o tipo de configuração amigável a multi-serviços que o Aspire orquestra. Tudo suporta .NET 10, 9, 8, 7, 6, Framework e Core, e roda em containers Linux, Azure, AWS e no local.
Alguns lugares para começar:
- IronPDF para HTML para PDF, edição de PDF, assinatura e formulários. O hub de tutoriais é o caminho mais rápido para um serviço de renderização funcional.
- IronOCR para extração de texto de imagens e PDFs em mais de 125 idiomas.
- IronXL para leitura/escrita de Excel sem Interop do Office.
- IronWord para geração e edição de DOCX.
- IronBarcode e IronQR para geração e escaneamento de códigos de barras e QR.
- Iron Suite se você precisar de mais de um dos acima.
Você pode obter uma chave de teste de 30 dias e ter um serviço de PDF ou OCR em execução dentro de um apphost Aspire em bem menos de uma hora. Se encontrar algo estranho, nosso time de suporte são engenheiros de verdade, não uma fila de triagem de tickets.
É isso. Nos vemos na próxima versão.