Description
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. Theappointments
andclients
strings in the above example refer to container names not database names. - All containers parented to the same
AddAzureCosmosDatabase
call share the sameCosmosClient
instance. This strategy can be used to associate the sameCosmosClientOptions
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