Aspire 13.2:.NET服务开发人员需要知道的事情
分享一些关于来自Iron Software工程团队的Aspire 13.2版本的笔记。 我们发布.NET库(IronPDF、IronOCR、IronXL、IronWord、IronBarcode和其他),几乎每个客户电话最终都会涉及分布式应用程序编排。 这就是为什么我们关注Aspire发布。 13.2是第一个让CLI感觉可以实际替代仪表板进行大多数日常工作的版本,并且有一些会在升级时让你吃瘪的重大变化。
这不是发布说明的复述。 官方新增功能页面有详细列表。这是工作代码库中真正有用的东西,以及需要注意的陷阱。
简而言之
- CLI现在真正可脚本化:分离模式,
aspire 停止,隔离模式,JSON输出 - 如果您想抛弃编排层的
.csproj,TypeScript AppHost处于预览模式 - 配置文件合并到
aspire.config.json(旧版文件自动迁移) - Foundry替代Azure AI Foundry。 这项变更会导致您的构建失败
WithBuildSecret- 服务发现环境变量现在使用方案,而不是端点名称(存在无声中断风险)
- 客户端集成中默认Azure凭证行为变更
CLI终于是一个CLI
这是标题。在13.2之前,aspire run阻碍了您的终端,仪表盘是管理运行中apphost的唯一现实选择。对于单人开发很好,但对于CI、集成测试或任何代理驱动的工作流程来说都很尴尬。
13.2修复了这个问题:
# Run in the background
aspire run --detach
# Or the new shortcut
aspire start
# See what's running
aspire ps
# Stop it
aspire 停止
aspire 停止 --all# Run in the background
aspire run --detach
# Or the new shortcut
aspire start
# See what's running
aspire ps
# Stop it
aspire 停止
aspire 停止 --all结合--format json(这会输出到stdout,而状态信息输出到stderr,如果您有管道到其他地方很重要),您可以围绕此构建真正的自动化。 aspire ps --resources --format json是编辑器集成和脚本的坚实构建块。
隔离模式是未被赞美的英雄
--isolated是我们一直在等待的那个。 它以随机化端口和隔离用户秘密运行一个apphost,防止端口冲突和配置冲突:
aspire run --isolated
aspire start --isolatedaspire run --isolated
aspire start --isolated如果您曾尝试同时运行同一个apphost的两个结帐,而不论是主分支对功能分支、并行集成测试,或代理驱动的工作流,您一定感受过这种痛苦。 随机端口加上分离的秘密意味着您终于可以随意启动N个副本而无需担心。
仅就git工作树而言,这就值得升级。 对于带有本地依赖的真实服务的集成测试套件(用于PDF生成的Chrome渲染、用于OCR的Tesseract、通常的重量级选手),这就是从不稳定到可靠的区别。
aspire doctor和aspire describe
aspire doctor运行通过您的环境:开发证书状态,容器运行版本,.NET SDK,WSL2配置,代理配置。 这是每个框架都应该拥有的功能,而大多数框架并没有费心去做。 输出是可操作的。 当出现问题时,它会告诉您该怎么做。
aspire describe --follow为您提供从终端内查看资源状态的持续流视图。 与仪表板显示的数据相同,但可以管道传输。 将其放入tmux窗格中,您将在80列中获得仪表板的大部分价值。
资源命令变得更整洁
旧的resource-start / resource-停止 / resource-restart命令已弃用,支持更清晰的子命令形式:
aspire resource api restart
aspire resource api rebuildaspire resource api restart
aspire resource api rebuildrebuild是新的。 它停止、构建并重新启动单个.NET项目资源,而无需拆除整个apphost会话。 如果您曾在12个资源图中更改了一个服务并抱怨重新启动一切,这就是解决方案。 我们自己也有这样的感受:当您对PDF渲染模板进行迭代或调整OCR预处理时,只为重新加载一个项目而重启整图非常耗时。
在不离开CLI的情况下处理秘密和证书
两个新的专用命令组:
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是更大的胜利。 它映射到与应用模型中的AddParameter(..., secret: true)一致的用户秘钥存储,但您无需安装.NET CLI即可管理它们。 在一个多语言apphost中,并非每个开发人员都有.NET SDK,这一点很重要。
aspire等待CI
aspire wait api --status healthy --timeout 120aspire wait api --status healthy --timeout 120阻止资源状态。 结合sleep 30 && hope。
配置:统领一切的文件
Aspire正在合并其配置文件。 旧的apphost.run.json之间的划分已被消除,取而代之的是项目根目录下的单个aspire.config.json。
{
"appHost": {
"path": "apphost.ts",
"language": "typescript/nodejs"
},
"sdk": { "version": "13.2.0" },
"channel": "stable",
"profiles": {
"default": {
"applicationUrl": "https://localhost:17000;http://localhost:15000"
}
}
}迁移是自动进行的。 您在现有项目中首次运行aspire命令时,旧文件会合并到新格式中,路径重新基于项目根目录。 旧版文件被保留,因此您仍然可以同时使用旧版CLI版本。全局设置(globalsettings.json)也会被迁移。
如果您有直接访问apphost.run.json的自动化,计划迁移它。
TypeScript AppHost(预览)
即使您不会在第一天使用它,这也很有趣。 您现在可以用TypeScript而不是C#编写您的apphost:
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();在幕后,TS apphost作为一个来宾进程运行,通过JSON-RPC在本地传输上与Aspire的.NET编排主机通信。 相同的资源模型,相同的仪表板,相同的集成,只是用TypeScript表达。
有趣的部分是代码生成。 当您运行aspire add时,CLI会检查集成的.NET程序集并生成一个TypeScript SDK到.modules/中。 aspire run上自动运行)。 13.2生成器还添加了Go、Java和Rust测试目标,这暗示了未来的发展方向。
对于像我们这样的.NET优先团队来说,这更像是"观看"而不是"发布",但代码生成模式意味着未来的多语言apphost语言都遵循相同的模型。 查看多语言架构文档以了解主机桥是如何工作的。
仪表板:遥测导入/导出是新的玩具
仪表板获得了真正的导入/导出工作流程。 从设置 → 管理中,选择资源和遥测类型,将它们导出为zip中的JSON文件。稍后重新导入到仪表板中,或将其交给其他人(或LLM)进行分析。
aspire export CLI命令生成相同的包:
aspire export --output .\artifacts\aspire-export.zip
aspire export <resource>aspire export --output .\artifacts\aspire-export.zip
aspire export <resource>对于错误报告非常有用。 不再是"这是一些截图和一个日志文件",您可以附上实际的遥测状态快照。
其他仪表板方面的注意事项:
- 您现在可以直接从仪表板界面设置资源参数,并有一个选项可以将其持久保存到用户秘密中
- 环境变量可以从资源详细信息视图中导出为
.env文件 - 资源图布局使用自适应力导向定位。 复杂的图形明显更整洁
/api/telemetry的遥测HTTP API返回OTLP JSON; 支持NDJSON流式传输的?follow=true。 端点覆盖资源、跨度、日志和跟踪(包括/traces/{traceId}用于完整跟踪查找)
独立仪表板现在默认将遥测API设置为关闭。 如果您自己托管仪表盘并依赖API, 您需要DASHBOARD__API__PRIMARYAPIKEY)。 AppHost集成方案仍然有效,因为Aspire.Hosting自动为工具接线API。
值得注意的应用模型位
WithMcpServer
您可以在应用模型中声明一个资源托管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")Aspire工具可以发现并代理该端点。 如果您正在推出任何向代码代理公开工具的产品,这是接线的最干净方式。 通过选项支持自定义路径或端点名称。
上下文端点解析
这是您不会注意到的东西,直到您需要它。 现在可以从特定调用者或网络的角度解析端点:
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
})相同的Redis端点将从主机进程解析为cache:6379,具体取决于上下文。 PublicInternet,如果您宁愿选择一个网络而不是一个调用者。
发布说明明确指出这些API在13.1中存在,但没有正确行为。 因此,如果您在13.1中编写了任何针对它们的内容,请重新测试。在资源层次结构文档中查看完整详细信息。
容器构建秘密
WithBuildSecret。 新名称更明确。 这些通过Docker/Podman作为正确的构建秘密流动,而不是构建参数(它们泄漏到镜像历史中)。
builder.AddContainer("worker", "contoso/worker")
.WithDockerfile("../worker")
.WithBuildSecret("ACCESS_TOKEN", accessToken);builder.AddContainer("worker", "contoso/worker")
.WithDockerfile("../worker")
.WithBuildSecret("ACCESS_TOKEN", accessToken);构建机密现在也可以是文件(例如,.npmrc用于容器构建中的私有注册表身份验证),这涵盖了大多数真实使用案例。
集成:重要的那些
完整列表很长。 这些是我会标记的:
- Docker Compose发布现在稳定(此前是预发布)。
docker-compose.yaml。当"部署到Azure"不是答案时,这是一个有用的逃生口。 值得注意的是,如果您正在提供包含本机依赖项的容器,因为IronPDF、IronOCR和IronXL都支持Linux容器和Docker,因此生成的编排文件通常无需手动调整即可正常工作。 - Azure虚拟网络集成(
AddPrivateEndpoint自动创建私有DNS区域、虚拟网络链接,并禁用目标的公共访问。 这是以前维护一个单独的Bicep文件所必需的那种东西。 - Azure数据湖存储获得了托管和客户端支持:
AddAzureDataLakeServiceClient/AddAzureDataLakeFileSystemClient。DI注册、重试、健康检查、遥测,常规Aspire堆栈。 - MongoDB EF Core有了一个新的客户端集成(
Aspire.MongoDB.EntityFrameworkCore)。 对于典型情况使用EnrichMongoDbContext<TContext>()。 - Azure AI推理现在支持嵌入,而不仅仅是聊天。 注册
IEmbeddingGenerator<string, Embedding<float>>。 也提供了键控变体。 - Azure容器注册表获得了
WithPurgeTask("0 1 * * *", ago: TimeSpan.FromDays(7), keep: 5),这将在cron计划上设置一个ACR清除任务。 - Bun支持通过
WithBun()支持JavaScript资源。 通过AddViteApp的Yarn可靠性。 - Microsoft Foundry替代Azure AI Foundry。
Aspire.Hosting.Azure.AIFoundry。 重大变化; 详情如下。
结合应用:Aspire 13.2中的文档服务
这是我们内部用于使用我们库测试分布式场景的模式。 值得展示,因为大多数新的13.2功能在这种多服务设置中付款,而不是在玩具演示中。
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()您从13.2中具体获得的内容:
aspire start --isolated允许您并行运行该图的两个副本而不会发生端口冲突。 在比较分支或对渲染器运行并行集成测试时非常有用- 当您更改Razor模板时,
aspire resource renderer rebuild只重新加载PDF渲染器,而不是整个图形颠簸 aspire wait renderer --status healthy --timeout 120允许您的CI阻塞,直到Chrome渲染初始化后再运行PDF生成测试- 遥测HTTP API和
aspire export为您提供每次渲染调用的OTLP格式跨度,这是您在生产流量中抓到慢CSS规则的方法 WithMcpServer允许您将渲染器作为MCP工具暴露用于编码代理工作流程,这对于构建任何以编程方式生成文档的东西很有用
如果您想构建上述渲染器这样的服务,IronPDF的HTML到PDF教程介绍了C#方面。对于OCR工作者,IronOCR入门指南涵盖了基础。
实际上会伤害您的重大变化
按您可能遭遇的可能性粗略排序:
服务发现环境变量命名
# 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使用端点方案替代端点名称。 如果您在代码或配置中匹配这些环境变量名称,请更新它。 这最有可能是无声的中断:没有抛出错误,变量只是拥有不同的键。
BeforeResourceStartedEvent
以前更广泛地触发; 现在仅在实际启动资源时触发,而不是在每个状态变化时触发。 如果您的处理程序依赖于以前的行为,它将静默停止运行。
从AIFoundry到Foundry
包和API重命名。 更新包引用和调用:
<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仍然适用于本地模型开发,但是当父资源配置为Foundry本地时,不支持Foundry项目。
默认Azure凭证
Aspire Azure客户端集成不再使用无参数的DefaultAzureCredential构造函数。 如果您依赖于除ManagedIdentityCredential之外的凭据在Azure服务中工作,行为将会改变。 在将生产升级之前,请阅读默认Azure凭证文档。
资源命令重命名
resource-start / resource-停止 / resource-restart 现在是aspire resource <name> start|停止|restart。 更新任何脚本。--project(仍然被接受)。
连接属性后缀
添加了一个连接属性后缀。 如果您直接访问连接属性(而不是通过WithReference),请检查您的代码仍然解析它们。
将 WithSecretBuildArg 重命名为 WithBuildSecret
如上所述。 直接重命名。
IAzureContainerRegistry 过时
请在计算环境上使用ContainerRegistry属性。
仪表板遥测 API 现在为选择性加入(独立)
已经在上面提到,但值得重复:现在需要明确启用独立仪表板部署的 API。
您应该升级吗?
对于在本地运行多服务应用程序的 .NET 商店,假设您已经清点上述中断更改,那么是的。 仅 CLI 的改进就值得。 尤其是分离模式和隔离模式修复了实际的工作流程问题。
对于 Foundry 用户:如果您想要此版本的新功能,则重命名是强制迁移,因此请做好相应的计划。
对于对 TypeScript 感兴趣的人:13.2 是第一个值得评估 TS apphost 的发布。 仍然是预览版,但值得一个周五下午。
如果您已经在 13.x 上,那么升级本身是一行代码:
aspire update --self
aspire updateaspire update --self
aspire update如果您在 12.x 或更早版本,请先访问 升级指南。有一个 13.0 步骤,您不能跳过。
补丁说明:13.2.1
自原始发布以来已经发布 13.2.1,包括可靠性修复。 有一个值得注意的小 TypeScript SDK 重命名,只在您已经使用 TS apphost 预览时重要:
| 之前 | 新 |
|---|---|
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在生成的SDK中保留为兼容性别名,因此不会导致运行时中断。
构建分布式 .NET 应用程序以处理文档工作负载?
如果您的服务进行 PDF 生成、OCR、Excel 处理、条码或我们涵盖的任何其他格式,我们的库专为 Aspire 编排的多服务、容器友好型设置而设计。 一切都支持 .NET 10、9、8、7、6、Framework 和 Core,并在 Linux 容器、Azure、AWS 和本地运行。
一些可以开始的地方:
- IronPDF 用于 HTML 到 PDF、PDF 编辑、签名和表单。 教程中心 是实现工作渲染服务的最快途径
- IronOCR 用于 125 多种语言的图像和 PDF 文字提取
- IronXL 用于不使用 Office Interop 的 Excel 读写
- IronWord 用于 DOCX 生成和编辑
- IronBarcode 和 IronQR 用于条码和 QR 生成及扫描
- Iron Suite 如果您需要上述多个
您可以获取 30 天试用密钥,并在不到一小时内在 Aspire apphost 内运行 PDF 或 OCR 服务。 如果您遇到任何问题,我们的支持团队是真正的工程师,而不是工单分诊队列。
就这样。 下次发布再见。
