Skip to content

[New article]: Document child resource support in hosting and client generations #2907

Closed
@captainsafia

Description

@captainsafia

Proposed topic or title

Child Resource Integration in .NET Aspire 9.2

Location in table of contents.

/ Integrations / Azure / Azure Cosmos DB
/ Integrations / Azure / Azure Service Bus
/ Integrations / Azure / Azure WebPub Sub

Reason for the article

In 9.1, we adeded support for modeling child resource dependencies on the host. In 9.2, we added support for modeling child resources on the client integrations. This issue outlines documenting the client integration portion.

Article abstract

Child resource support on the client integration side is a net new feature for:

  • Azure Cosmos DB integration
  • Azure WebPubSub integration
  • Azure Service Bus integration

Setting Up Azure Resources with Aspire AppHost

1. CosmosDB Integration

// Parent resource
var cosmos = builder.AddAzureCosmosDB("cosmos")
    .RunAsPreviewEmulator();
    
// Child resources
var database = cosmos.AddCosmosDatabase("appointments-app-db");
var container = database.AddContainer("appointments", "/id");

2. Service Bus Integration

// Parent resource
var serviceBus = builder.AddAzureServiceBus("servicebus");

// Child resource
var queue = serviceBus.AddServiceBusQueue("appointment-requests");

3. Web PubSub Integration

// Parent resource
var webpubsub = builder.AddAzureWebPubSub("webpubsub");

// Child resource
var hub = webpubsub.AddHub("apptnotifications");

Connecting Services to Resources

1. Reference-Based Resource Injection

builder.AddProject<Projects.AppointmentProcessor>("appointment-processor")
    .WithReference(database)
    .WithReference(queue)
    .WithReference(hub);

2. Role-Based Access Control

We should make a note that when used in conjunction with the new role-based access control APIs, the role assignments can only be applied on the parent resource. We don't yet support granular assignments on child resources.

In the example below, to set write access on the ServiceBus hub we apply the role assignment to its parent (servcieBus).

// Assigning service-specific roles
builder.AddProject<Projects.Api>("api")
    .WithReference(container)
    .WithReference(queue)
    .WithReference(hub)
    .WithRoleAssignments(webpubsub, WebPubSubBuiltInRole.WebPubSubContributor)
    .WithRoleAssignments(serviceBus, ServiceBusBuiltInRole.AzureServiceBusDataSender);

Client Integration in Services

1. Service Bus Client Integration

For Service Bus, there are no new APIs on the client integration. However, it is possible to WithReference a child resource then use the connection string connfiguration injected by the child resource reference. In the example below, we use the appointment-requests's resouce connection string to initialize the ServiceBus client.

// In Program.cs of a service
builder.AddAzureServiceBusClient("appointment-requests");

// Using the client in an endpoint
app.MapPost("/appointments", async (AppointmentRequest request, 
    ServiceBusClient client) => {
    // Send message to queue
});

2. CosmosDB Client Integration

The CosmosDB client integration has the following new APIs:

  • AddAzureCosmosContainer
  • AddKeyedAzureCosmosContainer
  • AddAzureCosmosDatabase
  • AddKeyedAzureCosmosDatabase

The AddAzureCosmosContainer and AddKeyedAzureCosmosContainer insert an instance the CosmosDB Container class into the DI container. In the example below, the AddAzureCosmosContainer method injects a Container instance that points to the container referenced in the appointments connection string.

// In Program.cs of a service
builder.AddAzureCosmosContainer("appointments");

// Using container in an endpoint
app.MapGet("/appointments", async (Container container) => {
    // Query data from container
});

The AddAzureCosmosDatabase and AddKeyedAzureCosmosDatabase overloads returns an instance of the new CosmosDatabaseBuilder API that can be used to attach multiple containers that are all part of the same database.

In the example below, we can inject Container instances associated with two different containers ("appointments" and "clients") in the same database.

// In Program.cs of a service
builder.AddAzureCosmosDatabase("appointments-app-db")
  .AddKeyedContainer("appointments")
  .AddKeyedContainer("clients");

// Using container in an endpoint
app.MapGet("/appointments", async (
    [FromKeyedServices("appointments")] Container container,
    [FromKeyedServices("clients")] Container container) => {
    // Query data from container
});

Some things to note about the CosmosDatabaseBuilder pattern:

  • In the scenario above, only the database (appointments-app-db) needs to be included as a reference in the AppHost. The appointments and clients strings in the above example refer to container names not database names.
  • All containers parented to the same AddAzureCosmosDatabase call share the same CosmosClient instance. This strategy can be used to associate the same CosmosClientOptions with multiple containers.

3. Web PubSub Client Integration

The WebPubSub integration supports two new overloads:

  • AddKeyedAzureWebPubSubServiceClient(string connectionName)
  • AddAzureWebPubSubServiceClient(string connectionName)

The connectionName that the overloads consume is the connection name associated with a child resource reference in the AppHost. In the example below, apptnotifications is the name of a WebPubSub Hub that has been referenced.

// In Program.cs of a service
builder.AddAzureWebPubSubServiceClient("apptnotifications");

// Using client to broadcast notifications
app.MapPost("/notify", async (WebPubSubServiceClient client, string message) => {
    await client.SendToGroupAsync("appointments", message);
});

The keyed variants of the overload are helpful when multiple hubs need to be referenced from the same application.

// In Program.cs of a service
builder.AddKeyedAzureWebPubSubServiceClient("apptnotifications");
builder.AddKeyedAzureWebPubSubServiceClient("chat");

// Using client to broadcast notifications
app.MapPost("/notify", async ([FromKeyedServices("apptnotifications")] WebPubSubServiceClient client, string message) => {
    await client.SendToGroupAsync("appointments", message);
});

// Using client to broadcast chat messages
app.MapPost("/notify", async ([FromKeyedServices("chat")] WebPubSubServiceClient client, string message) => {
    await client.SendToGroupAsync("message", message);
});

Relevant searches

No response


Associated WorkItem - 416512

Metadata

Metadata

Assignees

Labels

📌 seQUESTeredIdentifies that an issue has been imported into Quest.area-docsdoc-ideaIndicates issues that are suggestions for new topics [org][type][category]

Type

Projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions