行业新闻

Build 2025:Iron Software 客户的 AI 和 .NET 展望

分享一些关于来自Iron Software工程团队的Aspire 13.2版本的笔记。 我们发布.NET库(IronPDFIronOCRIronXLIronWordIronBarcode和其他),几乎每个客户电话最终都会涉及分布式应用程序编排。 这就是为什么我们关注Aspire发布。 13.2是第一个让CLI感觉可以实际替代仪表板进行大多数日常工作的版本,并且有一些会在升级时让你吃瘪的重大变化。

这不是发布说明的复述。 官方新增功能页面有详细列表。这是工作代码库中真正有用的东西,以及需要注意的陷阱。

简而言之

  • CLI现在真正支持脚本化:分离模式,aspire stop,隔离模式,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 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
SHELL

结合--format json(其将输出标准输出流而状态消息将输出到标准错误流,这在您将其管道传输到某处时很重要),您可以围绕此实现真正的自动化。 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-stop / 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文件从资源详细信息视图导出
  • 资源图布局使用自适应力导向定位。 复杂的图形明显更整洁
  • Telemetry HTTP API在/api/telemetry返回OTLP JSON; 支持?follow=true用于NDJSON流。 端点覆盖资源、跨度、日志和跟踪(包括用于完整跟踪查找的/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:6379PublicInternet,如果您更愿意选择网络而不是呼叫者。

发布说明明确指出这些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清除任务。
  • 通过WithBun()为JavaScript资源提供对Bun的支持。 通过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允许您并排运行该图形的两个副本而不会端口冲突。 在比较分支或对渲染器运行并行集成测试时非常有用
  • aspire resource renderer rebuild在您更改Razor模板时仅重新加载PDF渲染器,而不是整个图形
  • aspire wait renderer --status healthy --timeout 120允许您的CI阻塞,直到Chrome渲染初始化后再运行PDF生成测试
  • telemetery 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 Local时不支持Foundry Projects。

默认Azure凭证

Aspire Azure客户端集成不再使用无参数的DefaultAzureCredential构造函数。 如果您依赖于Azure服务中ManagedIdentityCredential之外的凭证,行为会发生变化。 在将生产升级之前,请阅读默认Azure凭证文档。

资源命令重命名

resource-start / resource-stop / resource-restart现在是aspire resource <name> start'|stop|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 服务。 如果您遇到任何问题,我们的支持团队是真正的工程师,而不是工单分诊队列。

就这样。 下次发布再见。