行业新闻

Aspire 13.2:.NET服务开发人员需要知道的事情

分享一些关于来自Iron Software工程团队的Aspire 13.2版本的笔记。 我们发布.NET库(IronPDFIronOCRIronXLIronWordIronBarcode和其他),几乎每个客户电话最终都会涉及分布式应用程序编排。 这就是为什么我们关注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
SHELL

结合--format json(这会输出到stdout,而状态信息输出到stderr,如果您有管道到其他地方很重要),您可以围绕此构建真正的自动化。 aspire ps --resources --format json是编辑器集成和脚本的坚实构建块。

隔离模式是未被赞美的英雄

--isolated是我们一直在等待的那个。 它以随机化端口和隔离用户秘密运行一个apphost,防止端口冲突和配置冲突:

aspire run --isolated
aspire start --isolated
aspire run --isolated
aspire start --isolated
SHELL

如果您曾尝试同时运行同一个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 rebuild
aspire resource api restart
aspire resource api rebuild
SHELL

rebuild是新的。 它停止、构建并重新启动单个.NET项目资源,而无需拆除整个apphost会话。 如果您曾在12个资源图中更改了一个服务并抱怨重新启动一切,这就是解决方案。 我们自己也有这样的感受:当您对PDF渲染模板进行迭代或调整OCR预处理时,只为重新加载一个项目而重启整图非常耗时。

在不离开CLI的情况下处理秘密和证书

两个新的专用命令组:

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
SHELL

aspire secret是更大的胜利。 它映射到与应用模型中的AddParameter(..., secret: true)一致的用户秘钥存储,但您无需安装.NET CLI即可管理它们。 在一个多语言apphost中,并非每个开发人员都有.NET SDK,这一点很重要。

aspire等待CI

aspire wait api --status healthy --timeout 120
aspire wait api --status healthy --timeout 120
SHELL

阻止资源状态。 结合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>
SHELL

对于错误报告非常有用。 不再是"这是一些截图和一个日志文件",您可以附上实际的遥测状态快照。

其他仪表板方面的注意事项:

  • 您现在可以直接从仪表板界面设置资源参数,并有一个选项可以将其持久保存到用户秘密中
  • 环境变量可以从资源详细信息视图中导出为.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")
$vbLabelText   $csharpLabel

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
})
$vbLabelText   $csharpLabel

相同的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);
$vbLabelText   $csharpLabel

构建机密现在也可以是文件(例如,.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()
$vbLabelText   $csharpLabel

您从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
SHELL

使用端点方案替代端点名称。 如果您在代码或配置中匹配这些环境变量名称,请更新它。 这最有可能是无声的中断:没有抛出错误,变量只是拥有不同的键。

BeforeResourceStartedEvent

以前更广泛地触发; 现在仅在实际启动资源时触发,而不是在每个状态变化时触发。 如果您的处理程序依赖于以前的行为,它将静默停止运行。

从AIFoundry到Foundry

包和API重命名。 更新包引用和调用:

<PackageReference Include="Aspire.Hosting.Foundry" Version="13.2.0" />
<PackageReference Include="Aspire.Hosting.Foundry" Version="13.2.0" />
XML
// 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)
$vbLabelText   $csharpLabel

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 update
aspire update --self
aspire update
SHELL

如果您在 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 生成和编辑
  • IronBarcodeIronQR 用于条码和 QR 生成及扫描
  • Iron Suite 如果您需要上述多个

您可以获取 30 天试用密钥,并在不到一小时内在 Aspire apphost 内运行 PDF 或 OCR 服务。 如果您遇到任何问题,我们的支持团队是真正的工程师,而不是工单分诊队列。

就这样。 下次发布再见。