Aspire 集成 Azure Cosmos DB 实战指南:深入解析 Aspire.Microsoft.Azure.Cosmos 组件
【免费下载链接】aspireAspire is the tool for code-first, extensible, observable dev and deploy.项目地址: https://gitcode.com/GitHub_Trending/as/aspire
本文以 .NET Aspire 仓库中的Aspire.Microsoft.Azure.Cosmos组件为核心,系统讲解如何通过依赖注入(DI)注册CosmosClient、以多种方式配置连接(连接字符串 / AccountEndpoint / 配置提供程序 / 内联委托)、启用健康检查与 OpenTelemetry 可观测性,以及在 AppHost 中使用Aspire.Hosting.Azure.CosmosDB编排 Azure Cosmos DB 资源(含本地模拟器)。读完本文,你将掌握在 Aspire 应用中开箱即用地连接 Azure Cosmos DB 的完整方案,并理解其底层实现原理。
组件定位与设计目标
Aspire.Microsoft.Azure.Cosmos是 Aspire 官方组件库(位于 src/Components)中面向 Azure Cosmos DB 的集成组件。它解决了手工实例化CosmosClient时的三类常见痛点:
- 注册与生命周期管理:将 CosmosClient 注册为 DI 容器中的单例(Singleton),并保证其在整个应用生命周期内只创建一次;
- 配置约定化:统一从
ConnectionStrings配置节或Aspire:Microsoft:Azure:Cosmos配置节读取连接信息,遵循 Aspire 的命名约定; - 可观测性开箱即用:自动关联健康检查、日志(Logging)与分布式追踪(Telemetry/Tracing),无需额外接线。
组件的核心入口是AspireMicrosoftAzureCosmosExtensions静态类(AspireMicrosoftAzureCosmosExtensions.cs),它向开发者暴露了一系列Add*扩展方法,全部作用于IHostApplicationBuilder。从方法签名可以看到,整个组件只依赖标准接口:
public static void AddAzureCosmosClient( this IHostApplicationBuilder builder, string connectionName, Action<MicrosoftAzureCosmosSettings>? configureSettings = null, Action<CosmosClientOptions>? configureClientOptions = null)内部流程非常清晰:先GetSettings读取并合并配置,再GetClientOptions构建CosmosClientOptions,然后注册单例并追加健康检查。下文将逐一展开。
快速开始:前置条件与安装
前置条件
- 一个Azure 订阅(可免费创建);
- 一个Azure Cosmos DB 账户(NoSQL API);
- 使用 .NET 8+ 与 Aspire 工作负载的宿主项目。
安装 NuGet 包
在需要使用 Cosmos DB 的服务项目(即调用AddAzureCosmosClient的项目)中执行:
dotnet add package Aspire.Microsoft.Azure.Cosmos注意:该包属于 Aspire 组件(Components),与用于编排资源的 Hosting 包(Aspire.Hosting.Azure.CosmosDB)职责不同,后者在“AppHost 扩展”一节单独讲解。两者的分工是:Hosting 包在 AppHost 中定义资源与连接关系,组件包在具体服务中消费连接。
注册与使用:把 CosmosClient 交给 DI
在承载服务的应用项目中(Aspire 当前模板为Program.cs,早期文档习惯称之为AppHost.cs),调用AddAzureCosmosClient即可注册CosmosClient:
builder.AddAzureCosmosClient("cosmosConnectionName");connectionName是连接名称,它同时用于在ConnectionStrings配置节中查找连接字符串。注册完成后,CosmosClient会以单例形式存在于 DI 容器中,任何构造函数注入即可获取,例如在一个 Web API 控制器中:
private readonly CosmosClient _client; public ProductsController(CosmosClient client) { _client = client; }更细粒度的注册:Container 与 Database
除CosmosClient外,组件还提供了直接注册Container和Database的方法(同样在 AspireMicrosoftAzureCosmosExtensions.cs 中定义):
AddAzureCosmosContainer(connectionName):注册Container单例,底层调用client.GetContainer(settings.DatabaseName, settings.ContainerName)。要求连接字符串中必须包含Database和Container名称,否则抛出InvalidOperationException(见源码中AddAzureCosmosContainer的校验逻辑);AddAzureCosmosDatabase(connectionName):注册Database单例,返回CosmosDatabaseBuilder以支持链式注册同一个数据库下的多个容器。数据库名称缺失时同样会抛异常(CosmosDatabaseBuilder.cs 中AddDatabase的校验逻辑)。
CosmosDatabaseBuilder支持对同一数据库注册多个键控(keyed)容器:
builder.AddAzureCosmosDatabase("cosmos") .AddKeyedContainer("orders") .AddKeyedContainer("products");AddKeyedContainer优先使用连接字符串中的Container名称,若未提供则回退到name参数(见 CosmosDatabaseBuilder.cs 中AddKeyedContainer的实现)。
键控注册(多个实例共存)
当应用中需要连接多个Cosmos DB 账户或数据库时,可以使用键控注册:
builder.AddKeyedAzureCosmosClient("inventory"); builder.AddKeyedAzureCosmosClient("analytics");它们分别以"inventory"、"analytics"为ServiceDescriptor.ServiceKey注册,消费时通过[FromKeyedServices("inventory")]或GetRequiredKeyedService<CosmosClient>("inventory")获取。同理也有AddKeyedAzureCosmosContainer与AddKeyedAzureCosmosDatabase。
连接配置详解:四种配置方式的完整继承
组件的配置目标是"要么提供AccountEndpoint,要么提供ConnectionString",二者必居其一;否则在解析客户端时会抛出InvalidOperationException(异常信息在 AspireMicrosoftAzureCosmosExtensions.cs 的GetCosmosClient方法末尾)。以下四种配置方式可以组合使用,优先级从低到高依次为:配置提供程序 → 连接字符串 → 内联委托。
方式一:使用连接字符串(ConnectionStrings 节)
在appsettings.json的ConnectionStrings节中按连接名称提供连接信息,代码中只需builder.AddAzureCosmosClient("cosmosConnectionName")即可自动拾取。支持两种格式。
(1)Account Endpoint(推荐)
仅提供账户端点 URI,配合MicrosoftAzureCosmosSettings.Credential属性完成认证。若未显式配置Credential,组件会依据当前环境自动创建默认的TokenCredential(即 DefaultAzureCredential 语义,兼容本地开发、Azure CLI、托管标识等场景):
{ "ConnectionStrings": { "cosmosConnectionName": "https://{account_name}.documents.azure.com:443/" } }(2)完整连接字符串
使用包含账户密钥的完整 Azure Cosmos DB 连接字符串:
{ "ConnectionStrings": { "cosmosConnectionName": "AccountEndpoint=https://{account_name}.documents.azure.com:443/;AccountKey={account_key};" } }测试代码(AspireMicrosoftAzureCosmosExtensionsTests.cs)证实连接字符串还支持附加Database=db;Container=mycontainer之类的子段,例如:
AccountEndpoint=https://localhost:8081;AccountKey=fake;Database=testdb;Container=mycontainers;解析逻辑(GetSettings中)会把这些子段提取并写入settings.DatabaseName与settings.ContainerName,供AddAzureCosmosContainer/AddAzureCosmosDatabase使用;DisableServerCertificateValidation=True等开关也可内联在连接字符串中。
方式二:使用配置提供程序(Aspire:Microsoft:Azure:Cosmos 节)
组件支持Microsoft.Extensions.Configuration的任意配置源(JSON、环境变量、用户机密等),统一从Aspire:Microsoft:Azure:Cosmos键加载MicrosoftAzureCosmosSettings。以下appsettings.json示例关闭了追踪:
{ "Aspire": { "Microsoft": { "Azure": { "Cosmos": { "DisableTracing": false } } } } }所有可配置项在 ConfigurationSchema.json 中有完整定义,与 MicrosoftAzureCosmosSettings.cs 的属性一一对应:
| 配置属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
ConnectionString | string | null | 要连接的 Cosmos DB 连接字符串(含密钥) |
AccountEndpoint | string (uri) | null | 账户端点 URI,如https://{account_name}.documents.azure.com;不得包含共享访问签名(SAS),需配合Credential使用 |
Credential | TokenCredential | null | 用于认证端点的凭据,缺省时自动创建默认凭据 |
DatabaseName | string | null | 要连接的数据库名称 |
ContainerName | string | null | 要连接的容器名称 |
DisableHealthChecks | boolean | false | 是否禁用健康检查 |
DisableTracing | boolean | false | 是否禁用 OpenTelemetry 追踪 |
此外,源码中的GetSettings还会尝试绑定Aspire:Microsoft:Azure:Cosmos:{connectionName}这一命名子节,因此不同连接可拥有各自独立的设置覆盖,这是容易被忽略但非常实用的特性。
方式三:使用内联委托(configureSettings)
AddAzureCosmosClient的可选参数Action<MicrosoftAzureCosmosSettings> configureSettings允许在代码中设置部分或全部设置项,它在配置绑定之后执行,因此优先级最高。例如在代码中禁用追踪:
builder.AddAzureCosmosClient("cosmosConnectionName", settings => settings.DisableTracing = true);方式四:配置 CosmosClientOptions(configureClientOptions)
第二个可选参数Action<CosmosClientOptions> configureClientOptions用于定制底层 SDK 的CosmosClientOptions。例如为所有请求的User-Agent附加ApplicationName后缀:
builder.AddAzureCosmosClient("cosmosConnectionName", configureClientOptions: clientOptions => clientOptions.ApplicationName = "myapp");从 AspireMicrosoftAzureCosmosExtensions.cs 的GetClientOptions可以看到几处关键的框架级强制设置:
- 分布式追踪默认开启:
clientOptions.CosmosClientTelemetryOptions.DisableDistributedTracing = false,这是日志与追踪生效的前提; - ApplicationName 拼接:组件会把内置的
CosmosApplicationName与你传入的ApplicationName拼接成"{CosmosApplicationName}/{ApplicationName}"格式,保证请求可归因; - 模拟器自动适配:检测到模拟器连接字符串时,自动设置
ConnectionMode.Gateway与LimitToEndpoint = true(详见下文模拟器一节)。
健康检查:让下游依赖感知 Cosmos 状态
默认情况下,组件会注册一个健康检查,其名称为Microsoft.Azure.Cosmos(源码中的HealthCheckName常量)。该检查通过调用CosmosClient.ReadAccountAsync()读取账户属性来验证账户可达性——实现见 AzureCosmosDbHealthCheck.cs,其注释说明该实现参照了 AspNetCore.Diagnostics.HealthChecks 的账户级探测模式,并对不支持CancellationToken的ReadAccountAsync通过WaitAsync做了取消支持。
健康检查会自动挂载到应用的/health端点。这意味着依赖方通过WaitFor等待服务 HTTP 健康(或 Kubernetes 就绪探针)时,在 Cosmos DB 不可达期间不会误报健康。键控注册时健康检查名称会带上服务键后缀(Microsoft.Azure.Cosmos_{serviceKey}),避免多个实例相互覆盖。
关闭健康检查
通过配置:
{ "Aspire": { "Microsoft": { "Azure": { "Cosmos": { "DisableHealthChecks": true } } } } }或通过内联委托:
builder.AddAzureCosmosClient("cosmosConnectionName", settings => settings.DisableHealthChecks = true);可观测性:日志与遥测
日志(Logging)
组件启用了 Cosmos DB 请求诊断日志。根据 ConfigurationSchema.json 中logLevel定义,可通过标准Logging:LogLevel配置控制名为Azure-Cosmos-Operation-Request-Diagnostics的日志类别:
{ "Logging": { "LogLevel": { "Azure-Cosmos-Operation-Request-Diagnostics": "Information" } } }遥测(Tracing)
当DisableTracing为false(默认)时,GetClientOptions会执行:
builder.Services.AddOpenTelemetry().WithTracing(tracerProviderBuilder => { tracerProviderBuilder.AddSource("Azure.Cosmos.Operation"); });即向 OpenTelemetry 的 TracerProvider 注册Azure.Cosmos.Operation这个 ActivitySource,将每个 Cosmos DB 操作的分布式追踪数据(延迟、状态、请求诊断等)接入 Aspire Dashboard 或其他 OpenTelemetry Collector。这使你在 Aspire 的仪表盘中可以直接按资源、按操作追踪到具体的 Cosmos 请求链路。
AppHost 扩展:用 Aspire.Hosting.Azure.CosmosDB 编排资源
前面所有内容都是"消费端"的工作;资源侧的编排由 Hosting 包完成。在AppHost 项目中安装:
dotnet add package Aspire.Hosting.Azure.CosmosDB然后在 AppHost 的Program.cs中定义 Cosmos DB 资源,并通过WithReference将连接信息注入服务项目:
var cosmosdb = builder.ExecutionContext.IsPublishMode ? builder.AddAzureCosmosDB("cdb").AddCosmosDatabase("cosmosdb") : builder.AddConnectionString("cosmosdb"); var myService = builder.AddProject<Projects.MyService>() .WithReference(cosmosdb);这里需要理解三个方法的分工:
AddAzureCosmosDB("cdb"):向应用模型添加一个 Azure Cosmos DB 资源(发布模式下会联动 Azure 预配逻辑,源码中AddAzureCosmosDB首先调用AddAzureProvisioning(),见 AzureCosmosDBExtensions.cs);AddCosmosDatabase("cosmosdb")进一步声明其中的数据库;AddConnectionString("cosmosdb"):从 AppHost 配置(例如用户机密)的ConnectionStrings:cosmosdb键读取现成的连接信息,适合本地开发不触发 Azure 预配的场景;WithReference(cosmosdb):把连接信息传递到MyService项目,在该项目中表现为名为cosmosdb的连接字符串。
在MyService项目的Program.cs中消费:
builder.AddAzureCosmosClient("cosmosdb");如此便完成了"AppHost 定义资源 → 注入连接 → 服务端注册客户端"的完整闭环。ExecutionContext.IsPublishMode分支保证了同一套代码在dotnet run(本地)与dotnet publish/azd deploy(发布)时分别走连接字符串与 Azure 资源两条路径。
使用本地模拟器(Emulator)
Aspire 支持通过本地容器运行 Azure Cosmos DB 模拟器,便于离线开发与测试。在 AppHost 中:
// AppHost var cosmosdb = builder.AddAzureCosmosDB("cosmos").RunAsEmulator();AppHost 启动时,会自动拉起一个运行 Azure Cosmos DB 的本地容器(默认使用 Linux 版 vNext 模拟器镜像)。服务端代码无需任何改动:
// Service code builder.AddAzureCosmosClient("cosmos");从 AzureCosmosDBExtensions.cs 的实现看,RunAsEmulator在IsPublishMode下会直接返回原资源(即发布时不启动模拟器);同时组件侧的GetClientOptions会检测模拟器连接字符串并自动切换ConnectionMode.Gateway与LimitToEndpoint = true,以匹配模拟器的网络模型。源码中还有RunAsClassicEmulator(经典版模拟器)与已标记[Obsolete]的RunAsPreviewEmulator(请改用RunAsEmulator),以及仅对 vNext 模拟器可用的WithDataExplorer(用于暴露 Data Explorer 端点,需配合ENABLE_EXPLORER环境变量)。
源码与测试佐证:行为是如何被保证的
组件的行为并非"文档承诺",而是有明确实现与测试约束的:
- 连接字符串解析:AspireMicrosoftAzureCosmosExtensionsTests.cs 中的
AddAzureCosmosClient_EnsuresConnectionStringIsCorrect用 7 组InlineData覆盖了含/不含AccountKey、Database、Container、DisableServerCertificateValidation及纯端点 URI 等组合,逐一断言最终client.Endpoint的规范化结果;AddAzureCosmosClient_FailsWithError则验证了非法连接字符串会抛出包含AccountEndpoint缺失信息的异常; - Database / Container 注册隔离:
AddAzureCosmosDatabase_RegistersDatabaseService断言注册数据库后容器中不存在裸CosmosClient单例(Assert.Null(client)),说明 Database/Container 注册并不向 DI 暴露多余的客户端实例,避免资源泄漏与误用; - 键控注册:
AddKeyedAzureCosmosDatabase_RegistersDatabaseService等测试验证了键控路径下服务键与实例的正确绑定; - 配置节绑定:
GetSettings中configSection.Bind(settings)与namedConfigSection.Bind(settings)的两次绑定,以及CosmosUtils.ParseConnectionString对连接字符串的解析,共同支撑了前文"多种配置方式可叠加、连接字符串子段可提取"的结论; - 健康检查:
AddCosmosHealthCheck在DisableHealthChecks为true时直接短路返回,避免无谓的注册开销。
这些测试位于 tests/Aspire.Microsoft.Azure.Cosmos.Tests 目录,是理解组件契约边界的最佳入口。
组件全景速查
| 关注点 | API / 配置 | 位置 |
|---|---|---|
| 注册客户端 | AddAzureCosmosClient/AddKeyedAzureCosmosClient | AspireMicrosoftAzureCosmosExtensions.cs |
| 注册容器 | AddAzureCosmosContainer/AddKeyedAzureCosmosContainer | 同上 |
| 注册数据库(多容器) | AddAzureCosmosDatabase+AddKeyedContainer | CosmosDatabaseBuilder.cs |
| 设置项 | Aspire:Microsoft:Azure:Cosmos(及命名子节) | MicrosoftAzureCosmosSettings.cs、ConfigurationSchema.json |
| 健康检查 | 默认启用,DisableHealthChecks关闭 | AzureCosmosDbHealthCheck.cs |
| 编排资源 | AddAzureCosmosDB/RunAsEmulator/WithReference | AzureCosmosDBExtensions.cs |
| 行为契约测试 | 连接解析 / 注册隔离 / 键控注册 | AspireMicrosoftAzureCosmosExtensionsTests.cs |
小结
Aspire.Microsoft.Azure.Cosmos组件用极简的 API 封装了 Azure Cosmos DB 接入的全部样板代码:单例注册、双轨认证(连接字符串 / AAD 凭据)、多容器编排、健康检查与 OpenTelemetry 追踪。配合Aspire.Hosting.Azure.CosmosDB的 AppHost 编排能力,开发者可以用同一套代码平滑地在本地模拟器、已配置连接字符串和 Azure 托管资源之间切换,这正是 Aspire"code-first、可扩展、可观测"开发与部署体验的典型体现。建议读者结合上述源码路径与测试用例进一步研读,在真实项目中优先采用 AccountEndpoint + 默认凭据的推荐配置,并保持健康检查默认开启以保障依赖拓扑的正确性。
【免费下载链接】aspireAspire is the tool for code-first, extensible, observable dev and deploy.项目地址: https://gitcode.com/GitHub_Trending/as/aspire
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考