Aspire TypeScript AppHost 指南:使用 Aspire.Hosting.CodeGeneration.TypeScript 生成类型化托管 API 绑定
发布时间:2026/9/18 5:38:06 锦皓数字建站

Aspire TypeScript AppHost 指南使用 Aspire.Hosting.CodeGeneration.TypeScript 生成类型化托管 API 绑定【免费下载链接】aspireAspire is the tool for code-first, extensible, observable dev and deploy.项目地址: https://gitcode.com/GitHub_Trending/as/aspireAspire 的Aspire.Hosting.CodeGeneration.TypeScript模块提供了一整套 TypeScript AppHost 脚手架与代码生成工具它根据 Aspire Type SystemATS元数据为用 TypeScript 编写 AppHost 提供类型安全的 SDK并通过 JSON-RPC 驱动 .NET AppHost 服务器。读完本文你将掌握从aspire init --language typescript初始化、理解脚手架产物、到通过aspire restore/aspire run管理生成绑定的完整工作流并了解生成的 TypeScript SDK 内部结构、类型映射规则与运行机制。这个模块到底是什么在深入代码之前先明确它的定位Aspire.Hosting.CodeGeneration.TypeScript是用 TypeScript 编写 AppHost的工具链而不是在 Aspire 中托管 JavaScript 或 TypeScript 应用的集成。区别很关键——它的服务对象是 AppHost应用程序编排宿主本身而不是业务应用。从仓库结构看该模块位于 src/Aspire.Hosting.CodeGeneration.TypeScript核心由以下几部分组成AtsTypeScriptCodeGenerator.cs实现ICodeGenerator接口的代码生成器负责产出整个 TypeScript SDKTypeScriptLanguageSupport.cs实现ILanguageSupport接口负责脚手架文件生成、语言检测与运行时配置TypeScriptApiProjector.cs负责将AtsContext解析为 TypeScript 特有的 API 决策类型映射、options 展平、回调塑形、Promise 包装Resources 下的base.mts、transport.mts、package.json等作为嵌入资源随包发布。此外csproj 文件 中有一个值得注意的细节该包设置了IsAspirePolyglotCompatiblefalse注释明确说明这是代码生成基础设施不是可发现的 polyglot 集成因此它不会出现在aspire add面向非 C# AppHost 的集成列表里——这正是 README 中不要用aspire add安装它的原因。快速开始初始化一个 TypeScript AppHost前置条件按照 README 与源码中 package.json 的 engines 字段你需要准备Aspire CLI提供aspire init、aspire restore、aspire run等命令受支持的 Node.js 运行时引擎约束为^20.19.0 || ^22.13.0 || 24该约束与 ESLint 10 的 Node 版本要求保持一致避免安装或运行时失败一个包管理器npm、pnpm 或 yarnCLI 会按已有 lockfile 识别。初始化命令在应用目录下执行aspire init --language typescriptCLI 会做两件事生成apphost.mts脚手架文件自动恢复restore本代码生成包——所以请勿用aspire add手动安装它。这里还有一个分支逻辑值得注意如果应用目录已经存在根级package.json所谓 brownfield 场景AppHost 会被创建在一个嵌套的aspire-apphost/包中避免与现有 Node.js 项目的包结构冲突。源码中通过IsNestedBrownfieldPackage检测目标目录名为aspire-apphost且其父目录存在package.json时即按嵌套包处理见 TypeScriptLanguageSupport.cs。最小 AppHost 程序脚手架生成的apphost.mts内容如下import { createBuilder } from ./.aspire/modules/aspire.mjs; const builder await createBuilder(); await builder.build().run();源码中脚手架的模板还附带了一些注释示例见 TypeScriptLanguageSupport.cs例如添加容器或 PostgreSQL// Add your resources here, for example: // const redis await builder.addContainer(cache, redis:latest); // const postgres await builder.addPostgres(db);注意createBuilder的导入路径是./.aspire/modules/aspire.mjs——这正是下一节要讲的生成绑定。脚手架产物全解析TypeScriptLanguageSupport.Scaffold方法源码一次会生成一组配套文件理解每个文件的用途对日常开发很有帮助文件作用apphost.mtsAppHost 入口导入生成的 SDK声明资源与编排逻辑package.json包清单含脚本与依赖详见下文tsconfig.apphost.json仅针对 AppHost 的 TypeScript 配置避免破坏已有项目的 tsconfig 设置eslint.config.mjsESLint 配置启用typescript-eslint/no-floating-promises让未 await 的 AppHost Promise 直接以 lint 错误暴露apphost.run.json运行配置文件包含随机生成的 Dashboard/OTLP/Resource Service 端口见下文.gitignore忽略node_modules/、dist/、.aspire/package.json 的脚本与依赖CreatePackageJson方法源码生成的脚本包括{ scripts: { aspire:lint: eslint apphost.mts, aspire:start: aspire run, aspire:build: tsc -p tsconfig.apphost.json, aspire:dev: tsc --watch -p tsconfig.apphost.json } }在全新非 brownfield项目下还会额外生成lint、dev、build、watch四个别名脚本。依赖方面运行时依赖vscode-jsonrpc^8.2.0JSON-RPC 传输层开发依赖包括types/node、eslint^10.0.3、nodemon、tsx^4.21.0、typescript^5.9.3与typescript-eslint。需要注意脚手架生成 package.json 时不会读取磁盘上已有的 package.json——所有合并工作由 CLI 侧的PackageJsonMerger负责避免二次合并导致依赖对象迭代顺序问题。apphost.run.json 的随机端口apphost.run.json通过AppHostProfilePortGenerator生成随机端口包含 https 配置文件{ profiles: { https: { applicationUrl: https://localhost:{DashboardHttpsPort};http://localhost:{DashboardHttpPort}, environmentVariables: { ASPIRE_DASHBOARD_OTLP_ENDPOINT_URL: https://localhost:{OtlpHttpsPort}, ASPIRE_RESOURCE_SERVICE_ENDPOINT_URL: https://localhost:{ResourceServiceHttpsPort} } } } }测试场景下可通过ScaffoldRequest.PortSeed固定随机种子保证端口可复现。生成的绑定Generated Bindings绑定从哪来apphost.mts导入的 SDK 位于.aspire/modules/目录它由两部分信息生成Aspire Type SystemATS元数据来自Aspire.Hosting及各个托管集成hosting integration——ATS 描述了每个托管 API 的类型、能力capability与参数aspire.config.json中配置的集成决定当前 AppHost 实际引入哪些集成及其能力。生成出的 SDK 提供 AppHost 使用的类型化 API并通过 JSON-RPC 调用 .NET AppHost 服务器。生成流程的主入口是 AtsTypeScriptCodeGenerator.GenerateDistributedApplication它会产出三个文件transport.mts传输层包含AspireClient、Handle、registerCallback、CancellationToken、CapabilityError等 JSON-RPC 通信原语base.mts基础类型库手工维护而非生成包含ReferenceExpression、AwaitableT、ResourceBuilderBase、AspireList/AspireDict等aspire.mts真正根据 ATS 元数据生成的 SDK即 AppHost 导入的文件。绑定管理命令命令作用aspire restore在 AppHost 目录下执行不启动 AppHost仅重新生成绑定aspire run启动 AppHost运行前同样会确保绑定是最新的铁律永远不要手编辑.aspire/modules/下的任何文件——它是生成产物。需要改变 API 行为时应该修改 AppHost 代码或调整aspire.config.json中的集成引用然后重新aspire restore。从生成文件的头部注释 GENERATED CODE - DO NOT EDIT 也能印证这一点。生成的 TypeScript SDK 内部结构与类型映射AtsTypeScriptCodeGenerator的 XML 文档注释源码完整记录了 ATS 到 TypeScript 的类型映射规则这是理解生成 SDK 的核心。基本类型映射ATS 类型TypeScript 类型stringstringnumbernumberbooleanbooleananyunknowncallback(context: EnvironmentContextHandle) PromisevoidT[]数组T[]映射后的类型数组Handle 类型命名规则ATS 类型 ID 使用{AssemblyName}/{TypeName}格式映射为 TypeScript 的 Handle 类型别名时遵循三条规则核心类型类型名 Handle例如Aspire.Hosting/IDistributedApplicationBuilder→BuilderHandle、Aspire.Hosting/DistributedApplication→ApplicationHandle、Aspire.Hosting/DistributedApplicationExecutionContext→ExecutionContextHandle接口类型接口名 Handle保留 I 前缀例如Aspire.Hosting.ApplicationModel/IResource→IResourceHandle资源类型类型名 BuilderHandle例如Aspire.Hosting.Redis/RedisResource→RedisResourceBuilderHandle、Aspire.Hosting/ContainerResource→ContainerResourceBuilderHandle。这些别名在GenerateHandleTypeAliases中生成形如type BuilderHandle HandleAspire.Hosting/IDistributedApplicationBuilder;源码属于内部类型用户实际接触的是包装类。Builder 类与 Promise 包装资源类型会生成对应的 builder 类及其 thenable 包装RedisResource→RedisResourceBuilder类 RedisResourceBuilderPromiseextends PromiseLikeRedisResourceBuilder这样 fluent 调用可以在未 await 的情况下继续链式书写接口类型生成抽象基类并以BuilderBase后缀命名例如IResource→ResourceBuilderBase具体 builder 依据类型继承层级扩展接口 builder实现具体继承抽象的类体系。生成器中还有一个AspireClient客户端类承载剩余的入口点方法entry point capabilities。从 TypeScriptApiProjector.cs 可以看到每个入口点函数都把client: AspireClientRpc作为第一个参数显式传入而AspireClientRpc的核心签名只有一个export interface AspireClientRpc { readonly connected: boolean; invokeCapabilityTResult unknown(capabilityId: string, args?: Recordstring, unknown): PromiseTResult; }也就是说一切 AppHost 操作最终都归结为对invokeCapability的 JSON-RPC 调用。方法命名与属性生成方法名默认派生自能力 ID如Aspire.Hosting.Redis/addRedis→addRedisTypeScript 侧统一使用 camelCase能力 ID 本身就是规范形式也可以通过[AspireExport(MethodName ...)]特性显式覆盖能力按PropertyGetter/PropertySetter/InstanceMethod/Method分类getter/setter 会按属性名分组合并生成{ get, set }形式的属性接口源码DTO 类型生成export interface所有属性均为可选propName?: type以允许部分对象且 PascalCase 属性名会被转换为 camelCase每个方法/属性都会携带从 ATS 元数据投影出的 JSDoc 文档注释包括param、returns、deprecated标记。文档与生成的代码永不漂移TypeScriptApiProjector有一个很有意思的设计保证见其 类注释它同时被AtsTypeScriptCodeGenerator生成实际 SDK和TypeScriptApiExportWriter生成规范 API 导出文档消费两者基于同一个解析结果输出因此文档中重建的签名与真实发布的 SDK 签名不可能漂移。这正是 README 中生成的 SDK稳定性的源码级保证。运行机制从 AppHost 到 .NET 服务器的执行链路TypeScriptLanguageSupport.GetRuntimeSpec源码定义了完整的运行契约阶段执行内容安装依赖npm installPreExecute执行前npx --no-install tsc --noEmit -p tsconfig.apphost.json类型检查Execute执行npx --no-install tsx --tsconfig tsconfig.apphost.json {appHostFile}WatchExecute监听模式nodemon监听ts,mts扩展名忽略node_modules/与.aspire/modules/每次变更先tsc --noEmit再通过tsx重启语言标识为typescript/nodejs格式{language}/{runtime}为将来支持typescript/bun、typescript/deno预留了扩展空间检测模式为apphost.mts与apphost.ts两种文件 必须存在package.json。另外模块通过NODE_EXTRA_CA_CERTS环境变量向 Node.js 注入 Aspire 的证书包CertificateBundleEnvironmentVariable保证 TLS 链路在本地开发环境可用该属性通过反射探测方式设置以保证与旧版 CLI 的兼容性。ReferenceExpression连接资源的表达式base.mts中定义的ReferenceExpression是生成 SDK 里非常实用的能力源码它允许把端点引用组合成表达式并在协议层序列化为$expr格式。其官方注释给出的示例const redis await builder.addRedis(cache); const endpoint await redis.getEndpoint(tcp); // Create a reference expression const expr refExprredis://${endpoint}:6379; // Use it in an environment variable await api.withEnvironment(REDIS_URL, expr);序列化后的 JSON 形如{ $expr: { format: redis://{0}:{1}, valueProviders: [ { $handle: Aspire.Hosting.ApplicationModel/EndpointReference:1 }, { $handle: Aspire.Hosting.ApplicationModel/EndpointReference:2 } ] } }条件表达式conditionwhenTrue/whenFalse同样受支持这让环境变量的取值可以跟随运行时条件动态解析。测试与验证体系仓库在 tests/Aspire.Hosting.CodeGeneration.TypeScript.Tests 下提供了完整的测试套件可作为你理解该模块行为的活文档TypeScriptLanguageSupportTests.cs验证脚手架输出的完整性与正确性——包括 package.json 的名称、脚本、engines.node约束、依赖版本、tsconfig.apphost.json的 outDir、ESLint 配置内容等还验证 brownfield 场景下输出仅包含 Aspire 想要的条目、不会破坏已有 package.jsonAtsTypeScriptCodeGeneratorTests.cs验证代码生成器输出Snapshots 目录存放快照测试基线如AtsGeneratedAspire.verified.ts整体生成的 SDK、WithPersistenceCapability.verified.txt、WithDataVolumeOptionsMerged.verified.tsoptions 展平等展示真实生成结果TestTypes测试用集成类型如TestRedisResource.cs、TestMarkerResource.cs用于验证各类能力的代码生成路径。注意事项与最佳实践不要用aspire add安装本包它通过aspire init --language typescript自动还原手动安装会破坏版本一致性不要编辑.aspire/modules/所有改动通过修改 AppHost 或aspire.config.json中的集成引用来完成随后执行aspire restore区分概念本模块服务于 TypeScript AppHost 的开发体验与托管 JS/TS 应用是两回事不要混淆使用场景Node 版本遵循^20.19.0 || ^22.13.0 || 24的引擎约束否则 ESLint 10 等工具链可能出现安装或运行失败brownfield 场景已有根package.json时 AppHost 会放入嵌套的aspire-apphost/包生成独立的tsconfig.apphost.json避免污染现有 TypeScript 配置。通过本文你可以完整掌握基于Aspire.Hosting.CodeGeneration.TypeScript的 TypeScript AppHost 开发流程从初始化、理解脚手架与生成绑定到读懂生成的 SDK 类型系统与运行链路。后续可以结合 src/Aspire.Hosting.CodeGeneration.TypeScript 的源码与 tests/Aspire.Hosting.CodeGeneration.TypeScript.Tests 的测试深入实践。【免费下载链接】aspireAspire is the tool for code-first, extensible, observable dev and deploy.项目地址: https://gitcode.com/GitHub_Trending/as/aspire创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。