diff --git a/docs/database/azure-cosmos-db-entity-framework-integration.md b/docs/database/azure-cosmos-db-entity-framework-integration.md index d6b18de7b7..d05181f287 100644 --- a/docs/database/azure-cosmos-db-entity-framework-integration.md +++ b/docs/database/azure-cosmos-db-entity-framework-integration.md @@ -1,7 +1,7 @@ --- title: .NET Aspire Cosmos DB Entity Framework Core integration 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. -ms.date: 02/26/2025 +ms.date: 04/01/2025 uid: dotnet/aspire/azure-cosmos-db-entity-framework-integration --- @@ -42,12 +42,18 @@ dotnet add package Aspire.Microsoft.EntityFrameworkCore.Cosmos ### Add Cosmos DB context -In the :::no-loc text="Program.cs"::: file of your client-consuming project, call the extension method to register a for use via the dependency injection container. The method takes a connection name parameter. +In the :::no-loc text="Program.cs"::: file of your client-consuming project, call the extension method to register a for use via the dependency injection container. The method takes a connection name parameter and a database name parameter. ```csharp builder.AddCosmosDbContext("cosmosdb", "databaseName"); ``` +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: + +```csharp +builder.AddCosmosDbContext("cosmosdb"); +``` + > [!TIP] > 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). diff --git a/docs/database/azure-cosmos-db-integration.md b/docs/database/azure-cosmos-db-integration.md index db311bbdbf..743daf007b 100644 --- a/docs/database/azure-cosmos-db-integration.md +++ b/docs/database/azure-cosmos-db-integration.md @@ -1,7 +1,7 @@ --- title: .NET Aspire Azure Cosmos DB integration 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. -ms.date: 02/26/2025 +ms.date: 04/01/2025 uid: dotnet/aspire/azure-cosmos-db-integration --- @@ -11,6 +11,8 @@ uid: dotnet/aspire/azure-cosmos-db-integration [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. +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). + ## Hosting integration [!INCLUDE [cosmos-app-host](includes/cosmos-app-host.md)] @@ -51,7 +53,7 @@ builder.AddAzureCosmosClient(connectionName: "cosmos-db"); > [!TIP] > 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). -You can then retrieve the instance using dependency injection. For example, to retrieve the connection from an example service: +You can then retrieve the instance using dependency injection. For example, to retrieve the client from an example service: ```csharp public class ExampleService(CosmosClient client) @@ -87,6 +89,142 @@ public class ExampleService( For more information on keyed services, see [.NET dependency injection: Keyed services](/dotnet/core/extensions/dependency-injection#keyed-services). +### Add Azure Cosmos DB database + + + +In the app host, the database resource () can be added as a child resource to the parent . In your client-consuming project, you can deep-link to the database resource by name, registering a instance for use with dependency injection. For example, consider the following code that calls `AddAzureCosmosDatabase` on an instance: + +```csharp +builder.AddAzureCosmosDatabase(connectionName: "customers"); +``` + + + +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 and database connection and `CosmosClient` instance. This strategy is useful when associating the same with multiple containers. + +After calling `AddAzureCosmosDatabase`, you can then retrieve the `Database` instance using dependency injection. For example, to retrieve the database from a delegate in a call consider the following code: + +```csharp +app.MapGet("/api/customers", async (Database database) => +{ + // Query data from database... +}); +``` + +### Add keyed Azure Cosmos DB database + + + +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 instance: + +```csharp +var builder = WebApplication.CreateBuilder(args); + +builder.AddKeyedAzureCosmosDatabase("customers"); +builder.AddKeyedAzureCosmosDatabase("orders"); + +var app = builder.Build(); + +app.MapGet("/api/customers", async ( + [FromKeyedServices("customers")] Database database) => +{ + // Get container from database and query data +}); + +app.MapPost("/api/orders", async ( + [FromKeyedServices("orders")] Database database, + [FromBody] OrderRequest order) => +{ + // Get container from database and query data +}); + +app.Run(); +``` + +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. + +### Add Azure Cosmos DB container + + + +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 . In your client-consuming project, you can deep-link to the container resource by name, registering a instance for use with dependency injection. For example, consider the following code that calls `AddAzureCosmosContainer` on an instance: + +```csharp +builder.AddAzureCosmosContainer(connectionName: "details"); +``` + +You can then retrieve the `Container` instance using dependency injection. For example, to retrieve the container from a delegate in a call consider the following code: + +```csharp +app.MapGet("/api/orders/{id:guid}", async ( + Container container, + [FromRoute] Guid id) => +{ + // Query data from container... +}); +``` + +### Add keyed Azure Cosmos DB container + + + +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 instance: + +```csharp +var builder = WebApplication.CreateBuilder(args); + +builder.AddKeyedAzureCosmosContainer("customers"); + +var app = builder.Build(); + +app.MapGet("/api/customers", async ( + [FromKeyedServices("customers")] Container container) => +{ + // Query data from container... +}); + +app.Run(); +``` + +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 and database connection. This strategy is useful when associating the same with multiple containers. Consider the following alternative code, to register multiple containers under the same database connection: + +```csharp +var builder = WebApplication.CreateBuilder(args); + +builder.AddAzureCosmosDatabase("customers", configureClientOptions: options => + { + options.SerializerOptions = new CosmosSerializationOptions() + { + PropertyNamingPolicy = CosmosPropertyNamingPolicy.CamelCase + }; + }) + .AddKeyedContainer(name: "profiles"); + +builder.AddAzureCosmosDatabase(connectionName: "orders") + .AddKeyedContainer(name: "details") + .AddKeyedContainer(name: "history"); + +var app = builder.Build(); + +app.MapGet("/api/customers", async ( + [FromKeyedServices("profiles")] Container container) => +{ + // Query data from container +}); + +app.MapGet("/api/orders", async ( + [FromKeyedServices("details")] Container container, + [FromKeyedServices("history")] Container container) => +{ + // Query data from container +}); + +app.Run(); +``` + +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. + ### Configuration 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 ## See also - [Azure Cosmos DB](https://azure.microsoft.com/services/cosmos-db) +- [Sample repository showing parent-child relationships](https://github.com/captainsafia/aspire-child-resources) - [.NET Aspire Cosmos DB Entity Framework Core integration](azure-cosmos-db-entity-framework-integration.md) - [.NET Aspire integrations overview](../fundamentals/integrations-overview.md) - [.NET Aspire Azure integrations overview](../azure/integrations-overview.md) diff --git a/docs/database/includes/cosmos-app-host.md b/docs/database/includes/cosmos-app-host.md index 89d7635890..ec1fc7dd77 100644 --- a/docs/database/includes/cosmos-app-host.md +++ b/docs/database/includes/cosmos-app-host.md @@ -5,6 +5,8 @@ ms.topic: include 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: - : Represents an Azure Cosmos DB resource. +- : Represents an Azure Cosmos DB container resource. +- : Represents an Azure Cosmos DB database resource. - : Represents an Azure Cosmos DB emulator resource. 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. @@ -105,13 +107,15 @@ The dependent resource can access the injected connection string by calling the ### Add Azure Cosmos DB database and container resources +.NET Aspire models parent child relationships between Azure Cosmos DB resources. For example, an Azure Cosmos DB account () can have multiple databases (), and each database can have multiple containers (). When you add a database or container resource, you do so on a parent resource. + To add an Azure Cosmos DB database resource, call the method on an `IResourceBuilder` instance: ```csharp var builder = DistributedApplication.CreateBuilder(args); var cosmos = builder.AddAzureCosmosDB("cosmos-db"); -cosmos.AddCosmosDatabase("db"); +var db = cosmos.AddCosmosDatabase("db"); // After adding all resources, run the app... ``` @@ -127,14 +131,44 @@ var builder = DistributedApplication.CreateBuilder(args); var cosmos = builder.AddAzureCosmosDB("cosmos-db"); var db = cosmos.AddCosmosDatabase("db"); -db.AddContainer("entries", "/id"); +var container = db.AddContainer("entries", "/id"); // After adding all resources, run the app... ``` -The container is created in the database that's represented by the `AzureCosmosDBDatabaseResource` that you added earlier. +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). + +#### Parent child resource relationship example + +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: + +```csharp +var builder = DistributedApplication.CreateBuilder(args); + +var cosmos = builder.AddAzureCosmosDB("cosmos"); + +var customers = cosmos.AddCosmosDatabase("customers"); +var profiles = customers.AddContainer("profiles", "/id"); + +var orders = cosmos.AddCosmosDatabase("orders"); +var details = orders.AddContainer("details", "/id"); +var history = orders.AddContainer("history", "/id"); + +builder.AddProject("api") + .WithReference(profiles) + .WithReference(details) + .WithReference(history); + +builder.Build().Run(); +``` + +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`. + +The following diagram illustrates the parent child relationship between the Azure Cosmos DB resources: + +:::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"::: -For more information, see [Databases, containers, and items in Azure Cosmos DB](/azure/cosmos-db/resource-model). +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 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 instance that connects to the `details` container. ### Add Azure Cosmos DB emulator resource diff --git a/docs/database/includes/media/cosmos-resource-relationships-thumb.png b/docs/database/includes/media/cosmos-resource-relationships-thumb.png new file mode 100644 index 0000000000..3a547fa1fa Binary files /dev/null and b/docs/database/includes/media/cosmos-resource-relationships-thumb.png differ diff --git a/docs/database/includes/media/cosmos-resource-relationships.excalidraw b/docs/database/includes/media/cosmos-resource-relationships.excalidraw new file mode 100644 index 0000000000..0076064c28 --- /dev/null +++ b/docs/database/includes/media/cosmos-resource-relationships.excalidraw @@ -0,0 +1,1017 @@ +{ + "type": "excalidraw", + "version": 2, + "source": "https://excalidraw.com", + "elements": [ + { + "id": "BetIdnuJVAsEvfFGxv3z6", + "type": "rectangle", + "x": 348.0752632417392, + "y": 75.95778493021734, + "width": 222.2791527694995, + "height": 71.7333455034731, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#a5d8ff", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "a2", + "roundness": { + "type": 3 + }, + "seed": 2079267916, + "version": 165, + "versionNonce": 1652020980, + "isDeleted": false, + "boundElements": [ + { + "type": "text", + "id": "BXbw_yfxj0B93dXb_UgFq" + }, + { + "id": "chAR-1rsc7Lz5cSklA66f", + "type": "arrow" + }, + { + "id": "KAeYgvQLsk7g-2wwXW4H4", + "type": "arrow" + } + ], + "updated": 1743532088033, + "link": null, + "locked": false + }, + { + "id": "BXbw_yfxj0B93dXb_UgFq", + "type": "text", + "x": 369.73493545168424, + "y": 84.8244576819539, + "width": 178.95980834960938, + "height": 54, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "a3", + "roundness": null, + "seed": 2008317556, + "version": 193, + "versionNonce": 866699340, + "isDeleted": false, + "boundElements": [], + "updated": 1743532086308, + "link": null, + "locked": false, + "text": "Customer Database\n\"customers\"", + "fontSize": 20, + "fontFamily": 6, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "BetIdnuJVAsEvfFGxv3z6", + "originalText": "Customer Database\n\"customers\"", + "autoResize": true, + "lineHeight": 1.35 + }, + { + "id": "ZU3FetO0xJojd3Oha8XrC", + "type": "rectangle", + "x": 900.1514216527121, + "y": 75.31335742581805, + "width": 214.6578694645427, + "height": 71.7333455034731, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#ffc9c9", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "a4", + "roundness": { + "type": 3 + }, + "seed": 584954572, + "version": 238, + "versionNonce": 2111329524, + "isDeleted": false, + "boundElements": [ + { + "type": "text", + "id": "jQ2fd3ucDH63pjUJIvctu" + }, + { + "id": "qpjk7KGMDPmEHp3VGv9m7", + "type": "arrow" + }, + { + "id": "09RFhqle1PAya4XMEkV8R", + "type": "arrow" + } + ], + "updated": 1743532141629, + "link": null, + "locked": false + }, + { + "id": "jQ2fd3ucDH63pjUJIvctu", + "type": "text", + "x": 935.6404287116436, + "y": 84.18003017755461, + "width": 143.6798553466797, + "height": 54, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "a5", + "roundness": null, + "seed": 89551220, + "version": 269, + "versionNonce": 1286166516, + "isDeleted": false, + "boundElements": [], + "updated": 1743531824565, + "link": null, + "locked": false, + "text": "Order Database\n\"orders\"", + "fontSize": 20, + "fontFamily": 6, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "ZU3FetO0xJojd3Oha8XrC", + "originalText": "Order Database\n\"orders\"", + "autoResize": true, + "lineHeight": 1.35 + }, + { + "id": "une2hoBfhcrggQ1PhV1tR", + "type": "rectangle", + "x": 286.06458413579264, + "y": 276.7456465575891, + "width": 345.01165597259416, + "height": 71.7333455034731, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#96f2d7", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "a6", + "roundness": { + "type": 3 + }, + "seed": 1286961484, + "version": 170, + "versionNonce": 82919924, + "isDeleted": false, + "boundElements": [ + { + "type": "text", + "id": "u7LSObHA8IaZai9QWKedt" + }, + { + "id": "KAeYgvQLsk7g-2wwXW4H4", + "type": "arrow" + } + ], + "updated": 1743532135042, + "link": null, + "locked": false + }, + { + "id": "u7LSObHA8IaZai9QWKedt", + "type": "text", + "x": 331.62054487355454, + "y": 285.61231930932564, + "width": 253.8997344970703, + "height": 54, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "a7", + "roundness": null, + "seed": 1935123572, + "version": 192, + "versionNonce": 1193860084, + "isDeleted": false, + "boundElements": [], + "updated": 1743532121611, + "link": null, + "locked": false, + "text": "Customer Profiles Container\n\"profiles\"", + "fontSize": 20, + "fontFamily": 6, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "une2hoBfhcrggQ1PhV1tR", + "originalText": "Customer Profiles Container\n\"profiles\"", + "autoResize": true, + "lineHeight": 1.35 + }, + { + "id": "9D8gv-h8iSsVeNTfNzb5y", + "type": "rectangle", + "x": 686.051613873488, + "y": 276.10121905318977, + "width": 291.03959772504965, + "height": 71.7333455034731, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#fff9db", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "a8", + "roundness": { + "type": 3 + }, + "seed": 617639884, + "version": 166, + "versionNonce": 1604913908, + "isDeleted": false, + "boundElements": [ + { + "type": "text", + "id": "14vJvqbbZIuVUVPitvLzU" + } + ], + "updated": 1743532078594, + "link": null, + "locked": false + }, + { + "id": "14vJvqbbZIuVUVPitvLzU", + "type": "text", + "x": 724.6215302286886, + "y": 284.9678918049263, + "width": 213.89976501464844, + "height": 54, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "a9", + "roundness": null, + "seed": 585635700, + "version": 198, + "versionNonce": 1157176308, + "isDeleted": false, + "boundElements": [], + "updated": 1743531877844, + "link": null, + "locked": false, + "text": "Order Details Container\n\"details\"", + "fontSize": 20, + "fontFamily": 6, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "9D8gv-h8iSsVeNTfNzb5y", + "originalText": "Order Details Container\n\"details\"", + "autoResize": true, + "lineHeight": 1.35 + }, + { + "id": "nEB5lm8By6Meay1Rg8Jlt", + "type": "rectangle", + "x": 1032.0665601979138, + "y": 276.7456465575891, + "width": 293.62341305430624, + "height": 71.7333455034731, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#fff5f5", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aA", + "roundness": { + "type": 3 + }, + "seed": 1531483724, + "version": 166, + "versionNonce": 1670389324, + "isDeleted": false, + "boundElements": [ + { + "type": "text", + "id": "Lp9UV-3QEa5eptlCOFk5n" + }, + { + "id": "09RFhqle1PAya4XMEkV8R", + "type": "arrow" + } + ], + "updated": 1743532172121, + "link": null, + "locked": false + }, + { + "id": "Lp9UV-3QEa5eptlCOFk5n", + "type": "text", + "x": 1070.7583707900083, + "y": 285.61231930932564, + "width": 216.2397918701172, + "height": 54, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aB", + "roundness": null, + "seed": 1765263988, + "version": 186, + "versionNonce": 2069938380, + "isDeleted": false, + "boundElements": [], + "updated": 1743531882885, + "link": null, + "locked": false, + "text": "Order History Container\n\"history\"", + "fontSize": 20, + "fontFamily": 6, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "nEB5lm8By6Meay1Rg8Jlt", + "originalText": "Order History Container\n\"history\"", + "autoResize": true, + "lineHeight": 1.35 + }, + { + "id": "chAR-1rsc7Lz5cSklA66f", + "type": "arrow", + "x": 626.9796183029686, + "y": -70.47443625087315, + "width": 172.96645180474576, + "height": 145.1276644030608, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aC", + "roundness": { + "type": 2 + }, + "seed": 217574604, + "version": 1062, + "versionNonce": 898774476, + "isDeleted": false, + "boundElements": [ + { + "type": "text", + "id": "IXfcsIfo2VgO3GSaGUbxG" + } + ], + "updated": 1743532277789, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + -115.56509263206794, + 43.88317681716592 + ], + [ + -172.96645180474576, + 145.1276644030608 + ] + ], + "lastCommittedPoint": null, + "startBinding": { + "elementId": "jbGlDS-ndKUGUhKtmmFVr", + "focus": -0.28932264734562113, + "gap": 1 + }, + "endBinding": { + "elementId": "BetIdnuJVAsEvfFGxv3z6", + "focus": -0.19985777113350967, + "gap": 3.9878770661829037 + }, + "startArrowhead": null, + "endArrowhead": "triangle", + "elbowed": false + }, + { + "id": "IXfcsIfo2VgO3GSaGUbxG", + "type": "text", + "x": 419.0207187387015, + "y": -2.0694712574785257, + "width": 79.09992980957031, + "height": 27, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aD", + "roundness": null, + "seed": 259439988, + "version": 13, + "versionNonce": 1772925900, + "isDeleted": false, + "boundElements": [], + "updated": 1743531693628, + "link": null, + "locked": false, + "text": "Contains", + "fontSize": 20, + "fontFamily": 6, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "chAR-1rsc7Lz5cSklA66f", + "originalText": "Contains", + "autoResize": true, + "lineHeight": 1.35 + }, + { + "id": "qpjk7KGMDPmEHp3VGv9m7", + "type": "arrow", + "x": 882.6586094806715, + "y": -70.47443625087317, + "width": 133.8355461871546, + "height": 142.08858775480422, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aE", + "roundness": { + "type": 2 + }, + "seed": 729314124, + "version": 813, + "versionNonce": 1004641356, + "isDeleted": false, + "boundElements": [ + { + "type": "text", + "id": "6aN3bZRSLclWSyXm4EM8N" + } + ], + "updated": 1743532277789, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 90.34434994151366, + 54.83859189195486 + ], + [ + 133.8355461871546, + 142.08858775480422 + ] + ], + "lastCommittedPoint": null, + "startBinding": { + "elementId": "jbGlDS-ndKUGUhKtmmFVr", + "focus": 0.07223642628949603, + "gap": 1 + }, + "endBinding": { + "elementId": "ZU3FetO0xJojd3Oha8XrC", + "focus": 0.22950794369676736, + "gap": 10.143362895292128 + }, + "startArrowhead": null, + "endArrowhead": "triangle", + "elbowed": false + }, + { + "id": "6aN3bZRSLclWSyXm4EM8N", + "type": "text", + "x": 965.6748614040347, + "y": -2.0694712574785257, + "width": 79.09992980957031, + "height": 27, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aF", + "roundness": null, + "seed": 1389686900, + "version": 13, + "versionNonce": 1535262452, + "isDeleted": false, + "boundElements": [], + "updated": 1743531693628, + "link": null, + "locked": false, + "text": "Contains", + "fontSize": 20, + "fontFamily": 6, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "qpjk7KGMDPmEHp3VGv9m7", + "originalText": "Contains", + "autoResize": true, + "lineHeight": 1.35 + }, + { + "id": "KAeYgvQLsk7g-2wwXW4H4", + "type": "arrow", + "x": 458.9506210487843, + "y": 148.00344284536283, + "width": 0.37993740529771003, + "height": 126.4448360534019, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aG", + "roundness": { + "type": 2 + }, + "seed": 1696868812, + "version": 499, + "versionNonce": 1096420684, + "isDeleted": false, + "boundElements": [ + { + "type": "text", + "id": "Kmh88U-Rb2hPDgI8gfkk7" + } + ], + "updated": 1743532121612, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + -0.3799374052976532, + 51.97062764952466 + ], + [ + -0.37993740529771003, + 126.4448360534019 + ] + ], + "lastCommittedPoint": null, + "startBinding": { + "elementId": "BetIdnuJVAsEvfFGxv3z6", + "focus": -0.0000024430666897761114, + "gap": 1 + }, + "endBinding": { + "elementId": "une2hoBfhcrggQ1PhV1tR", + "focus": 0.000001573983905659971, + "gap": 9.498936015644063 + }, + "startArrowhead": null, + "endArrowhead": "triangle", + "elbowed": false + }, + { + "id": "Kmh88U-Rb2hPDgI8gfkk7", + "type": "text", + "x": 419.0207187387015, + "y": 198.71838974514202, + "width": 79.09992980957031, + "height": 27, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aH", + "roundness": null, + "seed": 1686266740, + "version": 13, + "versionNonce": 1140611660, + "isDeleted": false, + "boundElements": [], + "updated": 1743531693628, + "link": null, + "locked": false, + "text": "Contains", + "fontSize": 20, + "fontFamily": 6, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "KAeYgvQLsk7g-2wwXW4H4", + "originalText": "Contains", + "autoResize": true, + "lineHeight": 1.35 + }, + { + "id": "S2TmZJ4RNJlXyh3YbdmBe", + "type": "arrow", + "x": 944.4467255196377, + "y": 147.3688785251296, + "width": 116.57014473472964, + "height": 126.06441154118451, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aI", + "roundness": { + "type": 2 + }, + "seed": 219484236, + "version": 611, + "versionNonce": 1851380084, + "isDeleted": false, + "boundElements": [ + { + "type": "text", + "id": "45FDc_REpZ_97kG_BzywH" + } + ], + "updated": 1743531954339, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + -72.919689567506, + 48.09415027229582 + ], + [ + -116.57014473472964, + 126.06441154118451 + ] + ], + "lastCommittedPoint": null, + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": "triangle", + "elbowed": false + }, + { + "id": "45FDc_REpZ_97kG_BzywH", + "type": "text", + "x": 792.0219757745863, + "y": 198.71838974514202, + "width": 79.09992980957031, + "height": 27, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aJ", + "roundness": null, + "seed": 1773082228, + "version": 13, + "versionNonce": 1279672436, + "isDeleted": false, + "boundElements": [], + "updated": 1743531693628, + "link": null, + "locked": false, + "text": "Contains", + "fontSize": 20, + "fontFamily": 6, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "S2TmZJ4RNJlXyh3YbdmBe", + "originalText": "Contains", + "autoResize": true, + "lineHeight": 1.35 + }, + { + "id": "09RFhqle1PAya4XMEkV8R", + "type": "arrow", + "x": 1068.2713705624049, + "y": 147.3688785251296, + "width": 113.65573117432155, + "height": 126.72916984732885, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aK", + "roundness": { + "type": 2 + }, + "seed": 52766412, + "version": 619, + "versionNonce": 903483892, + "isDeleted": false, + "boundElements": [ + { + "type": "text", + "id": "DQjdqQy3_nbOQs5wXxRPs" + } + ], + "updated": 1743532067390, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 80.96328401413325, + 53.249619474157186 + ], + [ + 113.65573117432155, + 126.72916984732885 + ] + ], + "lastCommittedPoint": null, + "startBinding": { + "elementId": "ZU3FetO0xJojd3Oha8XrC", + "focus": -0.03563365791928458, + "gap": 1 + }, + "endBinding": { + "elementId": "nEB5lm8By6Meay1Rg8Jlt", + "focus": 0.12400707216599659, + "gap": 9.498936015644063 + }, + "startArrowhead": null, + "endArrowhead": "triangle", + "elbowed": false + }, + { + "id": "DQjdqQy3_nbOQs5wXxRPs", + "type": "text", + "x": 1139.3288465407904, + "y": 198.71838974514202, + "width": 79.09992980957031, + "height": 27, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aL", + "roundness": null, + "seed": 2072709492, + "version": 12, + "versionNonce": 848507084, + "isDeleted": false, + "boundElements": [], + "updated": 1743531693628, + "link": null, + "locked": false, + "text": "Contains", + "fontSize": 20, + "fontFamily": 6, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "09RFhqle1PAya4XMEkV8R", + "originalText": "Contains", + "autoResize": true, + "lineHeight": 1.35 + }, + { + "id": "jbGlDS-ndKUGUhKtmmFVr", + "type": "rectangle", + "x": 586.8288113185816, + "y": -254.69543626543532, + "width": 332.32608370110074, + "height": 183.22100001456215, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#e7f5ff", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "groupIds": [ + "XElObUg25iqfyUHyTuTVl" + ], + "frameId": null, + "index": "aM", + "roundness": null, + "seed": 1229960652, + "version": 369, + "versionNonce": 591620980, + "isDeleted": false, + "boundElements": [ + { + "type": "text", + "id": "Npgxu_ENRoObT4I3NmU1L" + }, + { + "id": "chAR-1rsc7Lz5cSklA66f", + "type": "arrow" + }, + { + "id": "qpjk7KGMDPmEHp3VGv9m7", + "type": "arrow" + } + ], + "updated": 1743532277789, + "link": null, + "locked": false + }, + { + "id": "Npgxu_ENRoObT4I3NmU1L", + "type": "text", + "x": 626.981973103214, + "y": -230.58493625815424, + "width": 252.01976013183594, + "height": 135, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [ + "XElObUg25iqfyUHyTuTVl" + ], + "frameId": null, + "index": "aN", + "roundness": null, + "seed": 1564593012, + "version": 396, + "versionNonce": 1082143436, + "isDeleted": false, + "boundElements": [], + "updated": 1743532277789, + "link": null, + "locked": false, + "text": "\n\n\nAzure Cosmos DB Resource\n\"cosmos\"", + "fontSize": 20, + "fontFamily": 6, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "jbGlDS-ndKUGUhKtmmFVr", + "originalText": "\n\n\nAzure Cosmos DB Resource\n\"cosmos\"", + "autoResize": true, + "lineHeight": 1.35 + }, + { + "id": "oUBSF7qo9QB17fZeK8qO8", + "type": "image", + "x": 706.9228385836044, + "y": -239.6199881329922, + "width": 83.29079840430518, + "height": 83.29079840430518, + "angle": 0, + "strokeColor": "transparent", + "backgroundColor": "#ffffff", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "groupIds": [ + "XElObUg25iqfyUHyTuTVl" + ], + "frameId": null, + "index": "aO", + "roundness": null, + "seed": 1869988724, + "version": 188, + "versionNonce": 753545204, + "isDeleted": false, + "boundElements": null, + "updated": 1743532277789, + "link": null, + "locked": false, + "status": "saved", + "fileId": "a4c88afb146a3ec5eabbf5767977de165cc12c32", + "scale": [ + 1, + 1 + ], + "crop": null + } + ], + "appState": { + "gridSize": 20, + "gridStep": 5, + "gridModeEnabled": false, + "viewBackgroundColor": "#ffffff" + }, + "files": { + "a4c88afb146a3ec5eabbf5767977de165cc12c32": { + "mimeType": "image/png", + "id": "a4c88afb146a3ec5eabbf5767977de165cc12c32", + "dataURL": "data:image/png;base64,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", + "created": 1743532037162, + "lastRetrieved": 1743532037162 + } + } +} \ No newline at end of file diff --git a/docs/database/includes/media/cosmos-resource-relationships.png b/docs/database/includes/media/cosmos-resource-relationships.png new file mode 100644 index 0000000000..f9d29fb4a7 Binary files /dev/null and b/docs/database/includes/media/cosmos-resource-relationships.png differ diff --git a/docs/messaging/azure-service-bus-integration.md b/docs/messaging/azure-service-bus-integration.md index 33727e0a9c..63c9099eac 100644 --- a/docs/messaging/azure-service-bus-integration.md +++ b/docs/messaging/azure-service-bus-integration.md @@ -1,7 +1,7 @@ --- title: .NET Aspire Azure Service Bus integration description: Learn how to install and configure the .NET Aspire Azure Service Bus integration to connect to Azure Service Bus instances from .NET applications. -ms.date: 02/25/2025 +ms.date: 04/01/2025 --- # .NET Aspire Azure Service Bus integration @@ -15,6 +15,9 @@ ms.date: 02/25/2025 The .NET Aspire [Azure Service Bus](https://azure.microsoft.com/services/service-bus/) hosting integration models the various Service Bus resources as the following types: - : Represents an Azure Service Bus resource. +- : Represents an Azure Service Bus queue resource. +- : Represents an Azure Service Bus subscription resource. +- : Represents an Azure Service Bus topic resource. - : Represents an Azure Service Bus emulator resource. To access these types and APIs for expressing them, add the [📦 Aspire.Hosting.Azure.ServiceBus](https://www.nuget.org/packages/Aspire.Hosting.Azure.ServiceBus) NuGet package in the [app host](xref:dotnet/aspire/app-host) project. @@ -120,12 +123,12 @@ To add an Azure Service Bus queue, call the , it configures your Service Bus resources to have a queue named `queue`. The queue is created in the Service Bus namespace that's represented by the `AzureServiceBusResource` that you added earlier. For more information, see [Queues, topics, and subscriptions in Azure Service Bus](/azure/service-bus-messaging/service-bus-queues-topics-subscriptions). +When you call , it configures your Service Bus resources to have a queue named `queue`. The expresses an explicit parent-child relationship, between the `messaging` Service Bus resource and its child `queue`. The queue is created in the Service Bus namespace that's represented by the `AzureServiceBusResource` that you added earlier. For more information, see [Queues, topics, and subscriptions in Azure Service Bus](/azure/service-bus-messaging/service-bus-queues-topics-subscriptions). ### Add Azure Service Bus topic and subscription @@ -135,7 +138,7 @@ To add an Azure Service Bus topic, call the method providing a name: +When you add an Azure Web PubSub resource, you can also add a child hub resource. The hub resource is a logical grouping of connections and event handlers. To add an Azure Web PubSub hub resource to your app host project, chain a call to the method providing a resource and hub name: ```csharp var builder = DistributedApplication.CreateBuilder(args); @@ -68,12 +68,12 @@ var worker = builder.AddProject("worker") .WithExternalHttpEndpoints(); var webPubSub = builder.AddAzureWebPubSub("web-pubsub"); -var messagesHub = webPubSub.AddHub("messages"); +var messagesHub = webPubSub.AddHub(name: "messages", hubName: "messageHub"); // After adding all resources, run the app... ``` -The preceding code adds an Azure Web PubSub hub resource named `messages`, which enables the addition of event handlers. To add an event handler, call the : +The preceding code adds an Azure Web PubSub hub resource named `messages` and a hub name of `messageHub` , which enables the addition of event handlers. To add an event handler, call the : ```csharp var builder = DistributedApplication.CreateBuilder(args); @@ -82,7 +82,7 @@ var worker = builder.AddProject("worker") .WithExternalHttpEndpoints(); var webPubSub = builder.AddAzureWebPubSub("web-pubsub"); -var messagesHub = webPubSub.AddHub("messages"); +var messagesHub = webPubSub.AddHub(name: "messages", hubName: "messageHub"); messagesHub.AddEventHandler( $"{worker.GetEndpoint("https")}/eventhandler/", @@ -258,6 +258,12 @@ public class ExampleService( } ``` +If you want to register a single `WebPubSubServiceClient` instance with a specific connection name, there's an overload that uses the connection name as the service key. Call the `AddKeyedAzureWebPubSubServiceClient` method. This method registers the client as a singleton service in the dependency injection container. + +```csharp +builder.AddKeyedAzureWebPubSubServiceClient(connectionName: "web-pubsub"); +``` + For more information, see [Keyed services in .NET](/dotnet/core/extensions/dependency-injection#keyed-services). ### Configuration