Skip to content

Commit bfc80b7

Browse files
Add CosmosDB parent-child relationship bits. (#2912)
* Add CosmosDB parent-child relationship bits. Part of #2907 * A few fixes * Update docs/database/azure-cosmos-db-integration.md Co-authored-by: Safia Abdalla <[email protected]> * Update docs/database/azure-cosmos-db-integration.md Co-authored-by: Safia Abdalla <[email protected]> * A few updates based on feedback * Add a few more bits * Add more details about the web pubsub. * Apply suggestions from code review Co-authored-by: Safia Abdalla <[email protected]> --------- Co-authored-by: Safia Abdalla <[email protected]>
1 parent 3cbbfb3 commit bfc80b7

8 files changed

+1222
-17
lines changed

docs/database/azure-cosmos-db-entity-framework-integration.md

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
22
title: .NET Aspire Cosmos DB Entity Framework Core integration
33
description: Learn how to install and configure the .NET Aspire Cosmos DB Entity Framework Core integration to connect to existing Cosmos DB instances or create new instances from .NET with the Azure Cosmos DB emulator.
4-
ms.date: 02/26/2025
4+
ms.date: 04/01/2025
55
uid: dotnet/aspire/azure-cosmos-db-entity-framework-integration
66
---
77

@@ -42,12 +42,18 @@ dotnet add package Aspire.Microsoft.EntityFrameworkCore.Cosmos
4242

4343
### Add Cosmos DB context
4444

45-
In the :::no-loc text="Program.cs"::: file of your client-consuming project, call the <xref:Microsoft.Extensions.Hosting.AspireAzureEFCoreCosmosExtensions.AddCosmosDbContext%2A> extension method to register a <xref:System.Data.Entity.DbContext?displayProperty=fullName> for use via the dependency injection container. The method takes a connection name parameter.
45+
In the :::no-loc text="Program.cs"::: file of your client-consuming project, call the <xref:Microsoft.Extensions.Hosting.AspireAzureEFCoreCosmosExtensions.AddCosmosDbContext%2A> extension method to register a <xref:System.Data.Entity.DbContext?displayProperty=fullName> for use via the dependency injection container. The method takes a connection name parameter and a database name parameter.
4646

4747
```csharp
4848
builder.AddCosmosDbContext<MyDbContext>("cosmosdb", "databaseName");
4949
```
5050

51+
Alternatively, the database name can be inferred from the connection when there's a single database in the connection string. In this case, you can omit the database name parameter:
52+
53+
```csharp
54+
builder.AddCosmosDbContext<MyDbContext>("cosmosdb");
55+
```
56+
5157
> [!TIP]
5258
> The `connectionName` parameter must match the name used when adding the Cosmos DB resource in the app host project. In other words, when you call `AddAzureCosmosDB` and provide a name of `cosmosdb` that same name should be used when calling `AddCosmosDbContext`. For more information, see [Add Azure Cosmos DB resource](#add-azure-cosmos-db-resource).
5359

docs/database/azure-cosmos-db-integration.md

Lines changed: 141 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
22
title: .NET Aspire Azure Cosmos DB integration
33
description: Learn how to install and configure the .NET Aspire Azure Cosmos DB integration to connect to existing Cosmos DB instances or create new instances from .NET with the Azure Cosmos DB emulator.
4-
ms.date: 02/26/2025
4+
ms.date: 04/01/2025
55
uid: dotnet/aspire/azure-cosmos-db-integration
66
---
77

@@ -11,6 +11,8 @@ uid: dotnet/aspire/azure-cosmos-db-integration
1111

1212
[Azure Cosmos DB](https://azure.microsoft.com/services/cosmos-db/) is a fully managed NoSQL database service for modern app development. The .NET Aspire Azure Cosmos DB integration enables you to connect to existing Cosmos DB instances or create new instances from .NET with the Azure Cosmos DB emulator.
1313

14+
If you're looking for the Entity Framework Core integration, see [.NET Aspire Cosmos DB Entity Framework Core integration](azure-cosmos-db-entity-framework-integration.md).
15+
1416
## Hosting integration
1517

1618
[!INCLUDE [cosmos-app-host](includes/cosmos-app-host.md)]
@@ -51,7 +53,7 @@ builder.AddAzureCosmosClient(connectionName: "cosmos-db");
5153
> [!TIP]
5254
> The `connectionName` parameter must match the name used when adding the Cosmos DB resource in the app host project. In other words, when you call `AddAzureCosmosDB` and provide a name of `cosmos-db` that same name should be used when calling `AddAzureCosmosClient`. For more information, see [Add Azure Cosmos DB resource](#add-azure-cosmos-db-resource).
5355
54-
You can then retrieve the <xref:Azure.Cosmos.CosmosClient> instance using dependency injection. For example, to retrieve the connection from an example service:
56+
You can then retrieve the <xref:Azure.Cosmos.CosmosClient> instance using dependency injection. For example, to retrieve the client from an example service:
5557

5658
```csharp
5759
public class ExampleService(CosmosClient client)
@@ -87,6 +89,142 @@ public class ExampleService(
8789

8890
For more information on keyed services, see [.NET dependency injection: Keyed services](/dotnet/core/extensions/dependency-injection#keyed-services).
8991

92+
### Add Azure Cosmos DB database
93+
94+
<!-- TODO: Add xref to AddAzureCosmosDatabase when available -->
95+
96+
In the app host, the database resource (<xref:Aspire.Hosting.AzureCosmosDBDatabaseResource>) can be added as a child resource to the parent <xref:Aspire.Hosting.AzureCosmosDBResource>. In your client-consuming project, you can deep-link to the database resource by name, registering a <xref:Microsoft.Azure.Cosmos.Database> instance for use with dependency injection. For example, consider the following code that calls `AddAzureCosmosDatabase` on an <xref:Microsoft.Extensions.Hosting.IHostApplicationBuilder> instance:
97+
98+
```csharp
99+
builder.AddAzureCosmosDatabase(connectionName: "customers");
100+
```
101+
102+
<!-- TODO: Add xref to CosmosDatabaseBuilder when available -->
103+
104+
The `AddAzureCosmosDatabase` API returns a `CosmosDatabaseBuilder` instance that you can use to attach multiple containers under the same database connection. All child containers share the same <xref:Azure.Cosmos.CosmosClient> and database connection and `CosmosClient` instance. This strategy is useful when associating the same <xref:Azure.Cosmos.CosmosClientOptions> with multiple containers.
105+
106+
After calling `AddAzureCosmosDatabase`, you can then retrieve the `Database` instance using dependency injection. For example, to retrieve the database from a delegate in a <xref:Microsoft.AspNetCore.Builder.EndpointRouteBuilderExtensions.MapGet*> call consider the following code:
107+
108+
```csharp
109+
app.MapGet("/api/customers", async (Database database) =>
110+
{
111+
// Query data from database...
112+
});
113+
```
114+
115+
### Add keyed Azure Cosmos DB database
116+
117+
<!-- TODO: Add xref to AddKeyedAzureCosmosDatabase when available -->
118+
119+
There's also an `AddKeyedAzureCosmosDatabase` API that returns a `CosmosDatabaseBuilder` instance that you can use to attach multiple containers under the same database connection. method that allows you to register multiple databases with different connection names. For example, consider the following code that calls `AddKeyedAzureCosmosDatabase` on an <xref:Microsoft.Extensions.Hosting.IHostApplicationBuilder> instance:
120+
121+
```csharp
122+
var builder = WebApplication.CreateBuilder(args);
123+
124+
builder.AddKeyedAzureCosmosDatabase("customers");
125+
builder.AddKeyedAzureCosmosDatabase("orders");
126+
127+
var app = builder.Build();
128+
129+
app.MapGet("/api/customers", async (
130+
[FromKeyedServices("customers")] Database database) =>
131+
{
132+
// Get container from database and query data
133+
});
134+
135+
app.MapPost("/api/orders", async (
136+
[FromKeyedServices("orders")] Database database,
137+
[FromBody] OrderRequest order) =>
138+
{
139+
// Get container from database and query data
140+
});
141+
142+
app.Run();
143+
```
144+
145+
The preceding example code demonstrates how to register two databases, `details` and `customers`. Each named database can be used to get their corresponding containers to query data.
146+
147+
### Add Azure Cosmos DB container
148+
149+
<!-- TODO: Add xref to AddAzureCosmosContainer when available -->
150+
151+
When you add a Cosmos DB resource in the app host project, you can also add an Azure Cosmos DB container resource as well. The container resource is considered a child resource to the parent <xref:Aspire.Hosting.AzureCosmosDBDatabaseResource>. In your client-consuming project, you can deep-link to the container resource by name, registering a <xref:Microsoft.Azure.Cosmos.Container> instance for use with dependency injection. For example, consider the following code that calls `AddAzureCosmosContainer` on an <xref:Microsoft.Extensions.Hosting.IHostApplicationBuilder> instance:
152+
153+
```csharp
154+
builder.AddAzureCosmosContainer(connectionName: "details");
155+
```
156+
157+
You can then retrieve the `Container` instance using dependency injection. For example, to retrieve the container from a delegate in a <xref:Microsoft.AspNetCore.Builder.EndpointRouteBuilderExtensions.MapGet*> call consider the following code:
158+
159+
```csharp
160+
app.MapGet("/api/orders/{id:guid}", async (
161+
Container container,
162+
[FromRoute] Guid id) =>
163+
{
164+
// Query data from container...
165+
});
166+
```
167+
168+
### Add keyed Azure Cosmos DB container
169+
170+
<!-- TODO: Add xref to AddKeyedAzureCosmosContainer when available -->
171+
172+
There's also an `AddKeyedAzureCosmosContainer` method that allows you to register multiple containers with different connection names. For example, consider the following code that calls `AddKeyedAzureCosmosContainer` on an <xref:Microsoft.Extensions.Hosting.IHostApplicationBuilder> instance:
173+
174+
```csharp
175+
var builder = WebApplication.CreateBuilder(args);
176+
177+
builder.AddKeyedAzureCosmosContainer("customers");
178+
179+
var app = builder.Build();
180+
181+
app.MapGet("/api/customers", async (
182+
[FromKeyedServices("customers")] Container container) =>
183+
{
184+
// Query data from container...
185+
});
186+
187+
app.Run();
188+
```
189+
190+
If you have multiple containers under the same database connection, you can use the `AddAzureCosmosDatabase` API to attach multiple containers under the same database connection. All child containers share the same <xref:Azure.Cosmos.CosmosClient> and database connection. This strategy is useful when associating the same <xref:Azure.Cosmos.CosmosClientOptions> with multiple containers. Consider the following alternative code, to register multiple containers under the same database connection:
191+
192+
```csharp
193+
var builder = WebApplication.CreateBuilder(args);
194+
195+
builder.AddAzureCosmosDatabase("customers", configureClientOptions: options =>
196+
{
197+
options.SerializerOptions = new CosmosSerializationOptions()
198+
{
199+
PropertyNamingPolicy = CosmosPropertyNamingPolicy.CamelCase
200+
};
201+
})
202+
.AddKeyedContainer(name: "profiles");
203+
204+
builder.AddAzureCosmosDatabase(connectionName: "orders")
205+
.AddKeyedContainer(name: "details")
206+
.AddKeyedContainer(name: "history");
207+
208+
var app = builder.Build();
209+
210+
app.MapGet("/api/customers", async (
211+
[FromKeyedServices("profiles")] Container container) =>
212+
{
213+
// Query data from container
214+
});
215+
216+
app.MapGet("/api/orders", async (
217+
[FromKeyedServices("details")] Container container,
218+
[FromKeyedServices("history")] Container container) =>
219+
{
220+
// Query data from container
221+
});
222+
223+
app.Run();
224+
```
225+
226+
The preceding example code demonstrates how to register two databases, `customers` and `orders`, each with their own containers. The `customers` database has a single container named `profiles`, while the `orders` database has two containers named `details` and `history`. Each container can be queried individually using its respective key.
227+
90228
### Configuration
91229

92230
The .NET Aspire Azure Cosmos DB integration provides multiple options to configure the connection based on the requirements and conventions of your project.
@@ -201,6 +339,7 @@ The .NET Aspire Azure Cosmos DB integration currently doesn't support metrics by
201339
## See also
202340

203341
- [Azure Cosmos DB](https://azure.microsoft.com/services/cosmos-db)
342+
- [Sample repository showing parent-child relationships](https://github.com/captainsafia/aspire-child-resources)
204343
- [.NET Aspire Cosmos DB Entity Framework Core integration](azure-cosmos-db-entity-framework-integration.md)
205344
- [.NET Aspire integrations overview](../fundamentals/integrations-overview.md)
206345
- [.NET Aspire Azure integrations overview](../azure/integrations-overview.md)

docs/database/includes/cosmos-app-host.md

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ ms.topic: include
55
The .NET Aspire [Azure Cosmos DB](https://azure.microsoft.com/services/cosmos-db/) hosting integration models the various Cosmos DB resources as the following types:
66

77
- <xref:Aspire.Hosting.AzureCosmosDBResource>: Represents an Azure Cosmos DB resource.
8+
- <xref:Aspire.Hosting.Azure.AzureCosmosDBContainerResource>: Represents an Azure Cosmos DB container resource.
9+
- <xref:Aspire.Hosting.Azure.AzureCosmosDBDatabaseResource>: Represents an Azure Cosmos DB database resource.
810
- <xref:Aspire.Hosting.Azure.AzureCosmosDBEmulatorResource>: Represents an Azure Cosmos DB emulator resource.
911

1012
To access these types and APIs for expressing them, add the [📦 Aspire.Hosting.Azure.CosmosDB](https://www.nuget.org/packages/Aspire.Hosting.Azure.CosmosDB) NuGet package in the [app host](xref:dotnet/aspire/app-host) project.
@@ -103,13 +105,15 @@ The dependent resource can access the injected connection string by calling the
103105

104106
### Add Azure Cosmos DB database and container resources
105107

108+
.NET Aspire models parent child relationships between Azure Cosmos DB resources. For example, an Azure Cosmos DB account (<xref:Aspire.Hosting.AzureCosmosDBResource>) can have multiple databases (<xref:Aspire.Hosting.Azure.AzureCosmosDBDatabaseResource>), and each database can have multiple containers (<xref:Aspire.Hosting.Azure.AzureCosmosDBContainerResource>). When you add a database or container resource, you do so on a parent resource.
109+
106110
To add an Azure Cosmos DB database resource, call the <xref:Aspire.Hosting.AzureCosmosExtensions.AddCosmosDatabase*> method on an `IResourceBuilder<AzureCosmosDBResource>` instance:
107111

108112
```csharp
109113
var builder = DistributedApplication.CreateBuilder(args);
110114

111115
var cosmos = builder.AddAzureCosmosDB("cosmos-db");
112-
cosmos.AddCosmosDatabase("db");
116+
var db = cosmos.AddCosmosDatabase("db");
113117

114118
// After adding all resources, run the app...
115119
```
@@ -125,14 +129,44 @@ var builder = DistributedApplication.CreateBuilder(args);
125129

126130
var cosmos = builder.AddAzureCosmosDB("cosmos-db");
127131
var db = cosmos.AddCosmosDatabase("db");
128-
db.AddContainer("entries", "/id");
132+
var container = db.AddContainer("entries", "/id");
129133

130134
// After adding all resources, run the app...
131135
```
132136

133-
The container is created in the database that's represented by the `AzureCosmosDBDatabaseResource` that you added earlier.
137+
The container is created in the database that's represented by the `AzureCosmosDBDatabaseResource` that you added earlier. For more information, see [Databases, containers, and items in Azure Cosmos DB](/azure/cosmos-db/resource-model).
138+
139+
#### Parent child resource relationship example
140+
141+
To better understand the parent-child relationship between Azure Cosmos DB resources, consider the following example, which demonstrates adding an Azure Cosmos DB resource along with a database and container:
142+
143+
```csharp
144+
var builder = DistributedApplication.CreateBuilder(args);
145+
146+
var cosmos = builder.AddAzureCosmosDB("cosmos");
147+
148+
var customers = cosmos.AddCosmosDatabase("customers");
149+
var profiles = customers.AddContainer("profiles", "/id");
150+
151+
var orders = cosmos.AddCosmosDatabase("orders");
152+
var details = orders.AddContainer("details", "/id");
153+
var history = orders.AddContainer("history", "/id");
154+
155+
builder.AddProject<Projects.Api>("api")
156+
.WithReference(profiles)
157+
.WithReference(details)
158+
.WithReference(history);
159+
160+
builder.Build().Run();
161+
```
162+
163+
The preceding code adds an Azure Cosmos DB resource named `cosmos` with two databases: `customers` and `orders`. The `customers` database has a single container named `profiles`, while the `orders` database has two containers: `details` and `history`. The partition key for each container is `/id`.
164+
165+
The following diagram illustrates the parent child relationship between the Azure Cosmos DB resources:
166+
167+
:::image type="content" source="media/cosmos-resource-relationships-thumb.png" alt-text="A diagram depicting Azure Cosmos DB resource parent child relationships." lightbox="media/cosmos-resource-relationships.png":::
134168

135-
For more information, see [Databases, containers, and items in Azure Cosmos DB](/azure/cosmos-db/resource-model).
169+
When your app host code expresses parent-child relationships, the client can deep-link to these resources by name. For example, the `customers` database can be referenced by name in the client project, registering a <xref:Microsoft.Azure.Cosmos.Database> instance that connects to the `customers` database. The same applies to named containers, for example, the `details` container can be referenced by name in the client project, registering a <xref:Microsoft.Azure.Cosmos.Container> instance that connects to the `details` container.
136170

137171
### Add Azure Cosmos DB emulator resource
138172

78.6 KB
Loading

0 commit comments

Comments
 (0)