From f0a3544466a0c3097fd6143843b3ec5033448941 Mon Sep 17 00:00:00 2001 From: David Pine <david.pine.7@gmail.com> Date: Wed, 8 Jan 2025 12:17:43 -0600 Subject: [PATCH 1/8] Fixes #2308 --- .../azure-service-bus-integration.md | 434 ++++++++++++++---- .../Program.ConfigureServiceBusInfra.cs | 23 + 2 files changed, 368 insertions(+), 89 deletions(-) create mode 100644 docs/snippets/azure/AppHost/Program.ConfigureServiceBusInfra.cs diff --git a/docs/messaging/azure-service-bus-integration.md b/docs/messaging/azure-service-bus-integration.md index 88514c75af..50b3cc92b3 100644 --- a/docs/messaging/azure-service-bus-integration.md +++ b/docs/messaging/azure-service-bus-integration.md @@ -1,99 +1,364 @@ --- title: .NET Aspire Azure Service Bus integration -description: This article describes the .NET Aspire Azure Service Bus integration features and capabilities -ms.topic: how-to -ms.date: 08/12/2024 +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: 01/08/2025 --- # .NET Aspire Azure Service Bus integration -Cloud-native apps often require communication with messaging services such as [Azure Service Bus](/azure/service-bus-messaging/service-bus-messaging-overview). Messaging services help decouple applications and enable scenarios that rely on features such as queues, topics and subscriptions, atomic transactions, load balancing, and more. The .NET Aspire Service Bus integration handles the following concerns to connect your app to Azure Service Bus: +[!INCLUDE [includes-hosting-and-client](../includes/includes-hosting-and-client.md)] -- A <xref:Azure.Messaging.ServiceBus.ServiceBusClient> is registered in the DI container for connecting to Azure Service Bus. -- Applies `ServiceBusClient` configurations either inline through code or through configuration file settings. +[Azure Service Bus](https://azure.microsoft.com/services/service-bus/) is a fully managed enterprise message broker with message queues and publish-subscribe topics. The .NET Aspire Azure Service Bus integration enables you to connect to Azure Service Bus instances from .NET applications. -## Prerequisites +## Hosting integration -- Azure subscription - [create one for free](https://azure.microsoft.com/free/) -- Azure Service Bus namespace, learn more about how to [add a Service Bus namespace](/azure/service-bus-messaging/service-bus-dotnet-get-started-with-queues?#create-a-namespace-in-the-azure-portal). Alternatively, you can use a connection string, which is not recommended in production environments. +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: -## Get started +- <xref:Aspire.Hosting.Azure.AzureServiceBusResource>: Represents an Azure Service Bus resource. +- <xref:Aspire.Hosting.Azure.AzureServiceBusEmulatorResource>: Represents an Azure Service Bus emulator resource. -To get started with the .NET Aspire Azure Service Bus integration, install the [📦 Aspire.Azure.Messaging.ServiceBus](https://www.nuget.org/packages/Aspire.Azure.Messaging.ServiceBus) NuGet package in the client-consuming project, i.e., the project for the application that uses the Azure Service Bus client. +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. ### [.NET CLI](#tab/dotnet-cli) ```dotnetcli -dotnet add package Aspire.Azure.Messaging.ServiceBus +dotnet add package Aspire.Hosting.Azure.ServiceBus ``` ### [PackageReference](#tab/package-reference) ```xml -<PackageReference Include="Aspire.Azure.Messaging.ServiceBus" +<PackageReference Include="Aspire.Hosting.Azure.ServiceBus" Version="*" /> ``` ---- - For more information, see [dotnet add package](/dotnet/core/tools/dotnet-add-package) or [Manage package dependencies in .NET applications](/dotnet/core/tools/dependencies). -## Example usage +### Add Azure Service Bus resource -In the _:::no-loc text="Program.cs":::_ file of your client-consuming project, call the <xref:Microsoft.Extensions.Hosting.AspireServiceBusExtensions.AddAzureServiceBusClient%2A> extension to register a `ServiceBusClient` for use via the dependency injection container. +In your app host project, call <xref:Aspire.Hosting.AzureServiceBusExtensions.AddAzureServiceBus*> to add and return an Azure Service Bus resource builder. ```csharp -builder.AddAzureServiceBusClient("messaging"); +var builder = DistributedApplication.CreateBuilder(args); + +var serviceBus = builder.AddAzureServiceBus("messaging"); + +// After adding all resources, run the app... ``` -To retrieve the configured <xref:Azure.Messaging.ServiceBus.ServiceBusClient> instance using dependency injection, require it as a constructor parameter. For example, to retrieve the client from an example service: +When you add an <xref:Aspire.Hosting.Azure.AzureServiceBusResource> to the app host, it exposes other useful APIs to add queues and topics. In other words, you must add an `AzureServiceBusResource` before adding any of the other Service Bus resources. + +> [!IMPORTANT] When you call <xref:Aspire.Hosting.AzureServiceBusExtensions.AddAzureServiceBus*>, it implicitly calls <xref:Aspire.Hosting.AzureProvisionerExtensions.AddAzureProvisioning*>—which adds support for generating Azure resources dynamically during app startup. The app must configure the appropriate subscription and location. For more information, see [Configuration](../azure/local-provisioning.md#configuration). + +#### Generated provisioning Bicep + +If you're new to Bicep, it's a domain-specific language for defining Azure resources. With .NET Aspire, you don't need to write Bicep by-hand, instead the provisioning APIs generate Bicep for you. When you publish your app, the generated Bicep is output alongside the manifest file. When you add an Azure Service Bus resource, the following Bicep is generated: + +<!-- markdownlint-disable MD033 --> +<br/> +<details> +<summary id="service-bus-bicep"><strong>Toggle Azure Service Bus Bicep.</strong></summary> +<p aria-labelledby="service-bus-bicep"> + +:::code language="bicep" source="../snippets/azure/AppHost/service-bus.module.bicep"::: + +</p> +</details> +<!-- markdownlint-enable MD033 --> + +The preceding Bicep is a module that provisions an Azure Service Bus namespace with the following defaults: + +- `sku`: The SKU of the Service Bus namespace. The default is Standard. +- `location`: The location for the Service Bus namespace. The default is the resource group's location. + +In addition to the Service Bus namespace, it also provisions an Azure role-based access control (Azure RBAC) built-in role of Azure Service Bus Data Owner. The role is assigned to the Service Bus namespace's resource group. For more information, see [Azure Service Bus Data Owner](/azure/role-based-access-control/built-in-roles/integration#azure-service-bus-data-owner). + +#### Customize provisioning infrastructure + +All .NET Aspire Azure resources are subclasses of the <xref:Aspire.Hosting.Azure.AzureProvisioningResource> type. This type enables the customization of the generated Bicep by providing a fluent API to configure the Azure resources—using the <xref:Aspire.Hosting.AzureProvisioningResourceExtensions.ConfigureInfrastructure``1(Aspire.Hosting.ApplicationModel.IResourceBuilder{``0},System.Action{Aspire.Hosting.Azure.AzureResourceInfrastructure})> API. For example, you can configure the sku, location, and more. The following example demonstrates how to customize the Azure Service Bus resource: + +:::code language="csharp" source="../snippets/azure/AppHost/Program.ConfigureServiceBusInfra.cs" id="configure"::: + +The preceding code: + +- Chains a call to the <xref:Aspire.Hosting.AzureProvisioningResourceExtensions.ConfigureInfrastructure*> API: + - The infra parameter is an instance of the <xref:Aspire.Hosting.Azure.AzureResourceInfrastructure> type. + - The provisionable resources are retrieved by calling the <xref:Azure.Provisioning.Infrastructure.GetProvisionableResources> method. + - The single <xref:Azure.Provisioning.ServiceBus.ServiceBusNamespace> is retrieved. + - The <xref:Azure.Provisioning.ServiceBus.ServiceBusNamespace.Sku?displayProperty=nameWithType> is assigned to a <xref:Azure.Provisioning.ServiceBus.ServiceBusSku.Premium?displayProperty=nameWithType>. + - A tag is added to the Service Bus namespace with a key of `ExampleKey` and a value of `Example value`. + +There are many more configuration options available to customize the Azure Service Bus resource. For more information, see <xref:Azure.Provisioning.ServiceBus>. For more information, see [Azure.Provisioning customization](../azure/integrations-overview.md#azureprovisioning-customization). + +### Connect to an existing Azure Service Bus namespace + +You might have an existing Azure Service Bus namespace that you want to connect to. Instead of representing a new Azure Service Bus resource, you can add a connection string to the app host. To add a connection to an existing Azure Service Bus namespace, call the <xref:Aspire.Hosting.ParameterResourceBuilderExtensions.AddConnectionString*> method: ```csharp -public class ExampleService(ServiceBusClient client) +var builder = DistributedApplication.CreateBuilder(args); + +var serviceBus = builder.AddConnectionString("messaging"); + +builder.AddProject<Projects.WebApplication>("web") + .WithReference(serviceBus); + +// After adding all resources, run the app... +``` + +[!INCLUDE [connection-strings-alert](../includes/connection-strings-alert.md)] + +The connection string is configured in the app host's configuration, typically under [User Secrets](/aspnet/core/security/app-secrets), under the `ConnectionStrings` section. The app host injects this connection string as an environment variable into all dependent resources, for example: + +```json { - // ... + "ConnectionStrings": { + "messaging": "Endpoint=sb://{namespace}.servicebus.windows.net/;SharedAccessKeyName={key_name};SharedAccessKey={key_value};" + } } ``` -## App host usage +The dependent resource can access the injected connection string by calling the <xref:Microsoft.Extensions.Configuration.ConfigurationExtensions.GetConnectionString*> method, and passing the connection name as the parameter, in this case `"messaging"`. The `GetConnectionString` API is shorthand for `IConfiguration.GetSection("ConnectionStrings")[name]`. + +### Add Azure Service Bus queue resource + +To add an Azure Service Bus queue resource, chain a call on an `IResourceBuilder<AzureServiceBusResource>` to the <xref:Aspire.Hosting.AzureServiceBusExtensions.WithQueue*> API: + +```csharp +var builder = DistributedApplication.CreateBuilder(args); + +var serviceBus = builder.AddAzureServiceBus("messaging") + .WithQueue("queue"); + +// After adding all resources, run the app... +``` + +When you call `WithQueue`, 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). + +### Add Azure Service Bus topic resource + +To add an Azure Service Bus topic resource, chain a call on an `<IResourceBuilder<AzureServiceBusResource>>` to the <xref:Aspire.Hosting.AzureServiceBusExtensions.WithTopic*> API: + +```csharp +var builder = DistributedApplication.CreateBuilder(args); + +var serviceBus = builder.AddAzureServiceBus("messaging") + .WithTopic("topic"); + +// After adding all resources, run the app... +``` + +When you call `WithTopic`, it configures your Service Bus resources to have a topic named `topic`. The topic 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 subscription resource + +To add an Azure Service Bus subscription resource, chain a call on an `<IResourceBuilder<AzureServiceBusResource>>` to the <xref:Aspire.Hosting.AzureServiceBusExtensions.WithSubscription*> API: + +```csharp +var builder = DistributedApplication.CreateBuilder(args); + +var serviceBus = builder.AddAzureServiceBus("messaging") + .WithSubscription("topic", "subscription"); + +// After adding all resources, run the app... +``` + +When you call `WithSubscription`, it configures your Service Bus resources to have a subscription named `subscription` on the topic named `topic`. The subscription 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 emulator resource + +To add an Azure Service Bus emulator resource, chain a call on an `<IResourceBuilder<AzureServiceBusResource>>` to the `RunAsEmulator` API: + +```csharp +var builder = DistributedApplication.CreateBuilder(args); + +var serviceBus = builder.AddAzureServiceBus("messaging") + .RunAsEmulator(); + +// After adding all resources, run the app... +``` + +When you call `RunAsEmulator`, it configures your Service Bus resources to run locally using an emulator. The emulator in this case is the [Azure Service Bus Emulator](/azure/service-bus-messaging/overview-emulator). The Azure Service Bus Emulator provides a free local environment for testing your Azure Service Bus apps and it's a perfect companion to the .NET Aspire Azure hosting integration. The emulator isn't installed, instead, it's accessible to .NET Aspire as a container. When you add a container to the app host, as shown in the preceding example with the `mcr.microsoft.com/azure-messaging/servicebus-emulator` image (and the companion `mcr.microsoft.com/azure-sql-edge` image), it creates and starts the container when the app host starts. For more information, see [Container resource lifecycle](../fundamentals/app-host-overview.md#container-resource-lifecycle). + +#### Configure Service Bus emulator container + +There are various configurations available to container resources, for example, you can configure the container's ports or providing a wholistic JSON configuration which overrides everything. + +##### Configure Service Bus emulator container host port + +By default, the Service Bus emulator container when configured by .NET Aspire, exposes the following endpoints: + +| Endpoint | Image | Container port | Host port | +|--|--|--|--| +| `emulator` | `mcr.microsoft.com/azure-messaging/servicebus-emulator` | 5672 | dynamic | +| `tcp` | `mcr.microsoft.com/azure-sql-edge` | 1433 | dynamic | -To add Azure Service Bus hosting support to your <xref:Aspire.Hosting.IDistributedApplicationBuilder>, install 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. +The port that it's listening on is dynamic by default. When the container starts, the port is mapped to a random port on the host machine. To configure the endpoint port, chain calls on the container resource builder provided by the `RunAsEmulator` method as shown in the following example: + +```csharp +var builder = DistributedApplication.CreateBuilder(args); + +var serviceBus = builder.AddAzureServiceBus("messaging").RunAsEmulator( + emulator => + { + emulator.WithHostPort(7777); + }); + +// After adding all resources, run the app... +``` + +The preceding code configures the Service Bus emulator container's existing `emulator` endpoint to listen on port `5672`. The Service Bus emulator container's port is mapped to the host port as shown in the following table: + +| Endpoint name | Port mapping (`container:host`) | +|--------------:|---------------------------------| +| `https` | `8081:5672` | + +##### Configure Service Bus emulator container JSON configuration + +The Service Bus emulator container runs with a default [_config.json_](https://github.com/Azure/azure-service-bus-emulator-installer/blob/main/ServiceBus-Emulator/Config/Config.json) file. You can override this file entirely, or update the JSON configuration with a <xref:System.Text.Json.Nodes.JsonNode> representation of the configuration. + +To provide a custom JSON configuration file, call the `WithConfigurationFile` method: + +```csharp +var builder = DistributedApplication.CreateBuilder(args); + +var serviceBus = builder.AddAzureServiceBus("messaging").RunAsEmulator( + emulator => + { + emulator.WithConfigurationFile( + path: "./messaging/custom-config.json"); + }); +``` + +The preceding code configures the Service Bus emulator container to use a custom JSON configuration file located at `./messaging/custom-config.json`. To instead override specific properties in the default configuration, call the `WithConfiguration` method: + +```csharp +var builder = DistributedApplication.CreateBuilder(args); + +var serviceBus = builder.AddAzureServiceBus("messaging").RunAsEmulator( + emulator => + { + emulator.WithConfiguration( + (JsonNode configuration) => + { + var userConfig = configuration["UserConfig"]; + var ns = userConfig["Namespaces"][0]; + var firstQueue = ns["Queues"][0]; + var properties = firstQueue["Properties"]; + + properties["MaxDeliveryCount"] = 5; + properties["RequiresDuplicateDetection"] = true; + properties["DefaultMessageTimeToLive"] = "PT2H"; + }); + }); + +// After adding all resources, run the app... +``` + +The preceding code retrieves the `UserConfig` node from the default configuration. It then updates the first queue's properties to set the `MaxDeliveryCount` to `5`, `RequiresDuplicateDetection` to `true`, and `DefaultMessageTimeToLive` to `2 hours`. + +--> + +### Hosting integration health checks + +The Azure Service Bus hosting integration automatically adds a health check for the Service Bus resource. The health check verifies that the Service Bus is running and that a connection can be established to it. + +The hosting integration relies on the [📦 AspNetCore.HealthChecks.ServiceBus](https://www.nuget.org/packages/AspNetCore.HealthChecks.ServiceBus) NuGet package. + +## Client integration + +To get started with the .NET Aspire Azure Service Bus client integration, install the [📦 Aspire.Azure.Messaging.ServiceBus](https://www.nuget.org/packages/Aspire.Azure.Messaging.ServiceBus) NuGet package in the client-consuming project, that is, the project for the application that uses the Service Bus client. The Service Bus client integration registers a <xref:Azure.Messaging.ServiceBus.ServiceBusClient> instance that you can use to interact with Service Bus. ### [.NET CLI](#tab/dotnet-cli) ```dotnetcli -dotnet add package Aspire.Hosting.Azure.ServiceBus +dotnet add package Aspire.Azure.Messaging.ServiceBus ``` ### [PackageReference](#tab/package-reference) ```xml -<PackageReference Include="Aspire.Hosting.Azure.ServiceBus" +<PackageReference Include="Aspire.Azure.Messaging.ServiceBus" Version="*" /> ``` --- -In your app host project, register the Service Bus integration and consume the service using the following methods: +### Add Service Bus client + +In the :::no-loc text="Program.cs"::: file of your client-consuming project, call the <xref:Microsoft.Extensions.Hosting.AspireServiceBusExtensions.AddAzureServiceBusClient*> extension method on any <xref:Microsoft.Extensions.Hosting.IHostApplicationBuilder> to register a <xref:Azure.Messaging.ServiceBus.ServiceBusClient> for use via the dependency injection container. The method takes a connection name parameter. ```csharp -var builder = DistributedApplication.CreateBuilder(args); +builder.AddAzureServiceBusClient(connectionName: "messaging"); +``` + +> [!TIP] +> The `connectionName` parameter must match the name used when adding the Service Bus resource in the app host project. In other words, when you call `AddAzureServiceBus` and provide a name of `messaging` that same name should be used when calling `AddAzureServiceBusClient`. For more information, see [Add Azure Service Bus resource](#add-azure-service-bus-resource). -var serviceBus = builder.ExecutionContext.IsPublishMode - ? builder.AddAzureServiceBus("messaging") - : builder.AddConnectionString("messaging"); +You can then retrieve the <xref:Azure.Messaging.ServiceBus.ServiceBusClient> instance using dependency injection. For example, to retrieve the connection from an example service: -builder.AddProject<Projects.ExampleProject>() - .WithReference(serviceBus) +```csharp +public class ExampleService(ServiceBusClient client) +{ + // Use client... +} +``` + +For more information on dependency injection, see [.NET dependency injection](/dotnet/core/extensions/dependency-injection). + +### Add keyed Service Bus client + +There might be situations where you want to register multiple `ServiceBusClient` instances with different connection names. To register keyed Service Bus clients, call the <xref:Microsoft.Extensions.Hosting.AspireServiceBusExtensions.AddKeyedAzureServiceBusClient*> method: + +```csharp +builder.AddKeyedAzureServiceBusClient(name: "mainBus"); +builder.AddKeyedAzureServiceBusClient(name: "loggingBus"); +``` + +> [!IMPORTANT] +> When using keyed services, it's expected that your Service Bus resource configured two named buses, one for the `mainBus` and one for the `loggingBus`. + +Then you can retrieve the `ServiceBusClient` instances using dependency injection. For example, to retrieve the connection from an example service: + +```csharp +public class ExampleService( + [FromKeyedServices("mainBus")] ServiceBusClient mainBusClient, + [FromKeyedServices("loggingBus")] ServiceBusClient loggingBusClient) +{ + // Use clients... +} ``` -## Configuration +For more information on keyed services, see [.NET dependency injection: Keyed services](/dotnet/core/extensions/dependency-injection#keyed-services). + +### Configuration -The .NET Aspire Service Bus integration provides multiple options to configure the `ServiceBusClient` based on the requirements and conventions of your project. +The .NET Aspire Azure Service Bus integration provides multiple options to configure the connection based on the requirements and conventions of your project. -### Use configuration providers +#### Use a connection string + +When using a connection string from the `ConnectionStrings` configuration section, you can provide the name of the connection string when calling the <xref:Microsoft.Extensions.Hosting.AspireServiceBusExtensions.AddAzureServiceBusClient*> method: + +```csharp +builder.AddAzureServiceBusClient("messaging"); +``` -The Service Bus integration supports <xref:Microsoft.Extensions.Configuration?displayProperty=fullName>. It loads the `AzureMessagingServiceBusSettings` from _:::no-loc text="appsettings.json":::_ or other configuration files using `Aspire:Azure:Messaging:ServiceBus` key. +Then the connection string is retrieved from the `ConnectionStrings` configuration section: + +```json +{ + "ConnectionStrings": { + "messaging": "Endpoint=sb://{namespace}.servicebus.windows.net/;SharedAccessKeyName={keyName};SharedAccessKey={key};" + } +} +``` + +For more information on how to format this connection string, see the ConnectionString documentation. + +#### Use configuration providers + +The .NET Aspire Azure Service Bus integration supports <xref:Microsoft.Extensions.Configuration>. It loads the <xref:Aspire.Azure.Messaging.ServiceBus.AzureMessagingServiceBusSettings> from configuration by using the `Aspire:Azure:Messaging:ServiceBus` key. The following snippet is an example of a :::no-loc text="appsettings.json"::: file that configures some of the options: ```json { @@ -101,11 +366,8 @@ The Service Bus integration supports <xref:Microsoft.Extensions.Configuration?di "Azure": { "Messaging": { "ServiceBus": { - "DisableHealthChecks": true, - "DisableTracing": false, - "ClientOptions": { - "Identifier": "CLIENT_ID" - } + "ConnectionString": "Endpoint=sb://{namespace}.servicebus.windows.net/;SharedAccessKeyName={keyName};SharedAccessKey={key};", + "DisableTracing": false } } } @@ -113,46 +375,39 @@ The Service Bus integration supports <xref:Microsoft.Extensions.Configuration?di } ``` -If you have set up your configurations in the `Aspire:Azure:Messaging:ServiceBus` section of your _:::no-loc text="appsettings.json":::_ file you can just call the method `AddAzureServiceBusClient` without passing any parameters. +For the complete Service Bus client integration JSON schema, see [Aspire.Azure.Messaging.ServiceBus/ConfigurationSchema.json](https://github.com/dotnet/aspire/blob/v9.0.0/src/Components/Aspire.Azure.Messaging.ServiceBus/ConfigurationSchema.json). -### Use inline delegates +#### Use inline delegates -You can also pass the `Action<AzureMessagingServiceBusSettings>` delegate to set up some or all the options inline, for example to set the `FullyQualifiedNamespace`: +Also you can pass the `Action<AzureMessagingServiceBusSettings> configureSettings` delegate to set up some or all the options inline, for example to disable tracing from code: ```csharp builder.AddAzureServiceBusClient( "messaging", - static settings => settings.FullyQualifiedNamespace = "YOUR_SERVICE_BUS_NAMESPACE"); + static settings => settings.DisableTracing = true); ``` -You can also set up the [ServiceBusClientOptions](/dotnet/api/azure.messaging.servicebus.servicebusclientoptions) using `Action<IAzureClientBuilder<ServiceBusClient, ServiceBusClientOptions>>` delegate, the second parameter of the `AddAzureServiceBus` method. For example to set the `ServiceBusClient` ID to identify the client: +You can also set up the <xref:Azure.Messaging.ServiceBus.ServiceBusClientOptions?displayProperty=fullName> using the optional `Action<ServiceBusClientOptions> configureClientOptions` parameter of the `AddAzureServiceBusClient` method. For example to set the <xref:Azure.Messaging.ServiceBus.ServiceBusClientOptions.Identifier?displayProperty=nameWithType> user-agent header suffix for all requests issues by this client: ```csharp builder.AddAzureServiceBusClient( "messaging", - static clientBuilder => - clientBuilder.ConfigureOptions( - static options => options.Identifier = "CLIENT_ID")); + configureClientOptions: + clientOptions => clientOptions.Identifier = "myapp"); ``` -### Configuration options +### Client integration health checks -The following configurable options are exposed through the <xref:Aspire.Azure.Messaging.ServiceBus.AzureMessagingServiceBusSettings> class: +By default, .NET Aspire integrations enable health checks for all services. For more information, see [.NET Aspire integrations overview](../fundamentals/integrations-overview.md). -| Name | Description | -|--|--| -| `ConnectionString` | The connection string used to connect to the Service Bus namespace. | -| `Credential` | The credential used to authenticate to the Service Bus namespace. | -| `FullyQualifiedNamespace` | The fully qualified Service Bus namespace. | -| `DisableTracing` | Disables tracing for the Service Bus client. | -| **<sup>†</sup>**`HealthCheckQueueName` | The name of the queue used for health checks. | -| **<sup>†</sup>**`HealthCheckTopicName` | The name of the topic used for health checks. | +The .NET Aspire Azure Service Bus integration: -_**<sup>†</sup>** At least one of the name options are mandatory when enabling health checks._ +- Adds the health check when <xref:Aspire.Azure.Messaging.ServiceBus.AzureMessagingServiceBusSettings.DisableTracing?displayProperty=nameWithType> is `false`, which attempts to connect to the Service Bus. +- Integrates with the `/health` HTTP endpoint, which specifies all registered health checks must pass for app to be considered ready to accept traffic. [!INCLUDE [integration-observability-and-telemetry](../includes/integration-observability-and-telemetry.md)] -### Logging +#### Logging The .NET Aspire Azure Service Bus integration uses the following log categories: @@ -160,29 +415,27 @@ The .NET Aspire Azure Service Bus integration uses the following log categories: - `Azure.Identity` - `Azure-Messaging-ServiceBus` -### Tracing - -> [!NOTE] -> Service Bus `ActivitySource` support in the Azure SDK for .NET is experimental, and the shape of activities may change in the future without notice. +In addition to getting Azure Service Bus request diagnostics for failed requests, you can configure latency thresholds to determine which successful Azure Service Bus request diagnostics will be logged. The default values are 100 ms for point operations and 500 ms for non point operations. -You can enable tracing in several ways: - -- Setting the `Azure.Experimental.EnableActivitySource` [runtime configuration setting](/dotnet/core/runtime-config/) to `true`. Which can be done with either: - - Call `AppContext.SetSwitch("Azure.Experimental.EnableActivitySource", true);`. - - Add the `RuntimeHostConfigurationOption` setting to your project file: - - ```xml - <ItemGroup> - <RuntimeHostConfigurationOption - Include="Azure.Experimental.EnableActivitySource" - Value="true" /> - </ItemGroup> - ``` +```csharp +builder.AddAzureServiceBusClient( + "messaging", + configureClientOptions: + clientOptions => { + clientOptions.ServiceBusClientTelemetryOptions = new() + { + ServiceBusThresholdOptions = new() + { + PointOperationLatencyThreshold = TimeSpan.FromMilliseconds(50), + NonPointOperationLatencyThreshold = TimeSpan.FromMilliseconds(300) + } + }; + }); +``` -- Set the `AZURE_EXPERIMENTAL_ENABLE_ACTIVITY_SOURCE` environment variable to "true". - - Can be achieved by chaining a call to `WithEnvironment("AZURE_EXPERIMENTAL_ENABLE_ACTIVITY_SOURCE", "true")` +#### Tracing -When enabled, the .NET Aspire Azure Service Bus integration will emit the following tracing activities using OpenTelemetry: +The .NET Aspire Azure Service Bus integration will emit the following tracing activities using OpenTelemetry: - `Message` - `ServiceBusSender.Send` @@ -205,18 +458,21 @@ When enabled, the .NET Aspire Azure Service Bus integration will emit the follow - `ServiceBusRuleManager.DeleteRule` - `ServiceBusRuleManager.GetRules` -For more information, see: +Azure Service Bus tracing is currently in preview, so you must set the experimental switch to ensure traces are emitted. + +```csharp +AppContext.SetSwitch("Azure.Experimental.EnableActivitySource", true); +``` -- [Azure SDK for .NET: Distributed tracing and the Service Bus client](https://github.com/Azure/azure-sdk-for-net/blob/Azure.Messaging.ServiceBus_7.17.5/sdk/servicebus/Azure.Messaging.ServiceBus/TROUBLESHOOTING.md#distributed-tracing). -- [Azure SDK for .NET: OpenTelemetry configuration](https://github.com/Azure/azure-sdk-for-net/blob/main/sdk/core/Azure.Core/samples/Diagnostics.md#opentelemetry-configuration). -- [Azure SDK for .NET: Enabling experimental tracing features](https://github.com/Azure/azure-sdk-for-net/blob/main/sdk/core/Azure.Core/samples/Diagnostics.md#enabling-experimental-tracing-features). +For more information, see [Azure Service Bus SDK observability: Trace attributes](/azure/service-bus/nosql/sdk-observability?tabs=dotnet#trace-attributes). -### Metrics +#### Metrics -The .NET Aspire Azure Service Bus integration currently doesn't support metrics by default due to limitations with the Azure SDK for .NET. If that changes in the future, this section will be updated to reflect those changes. +The .NET Aspire Azure Service Bus integration currently doesn't support metrics by default due to limitations with the Azure SDK. ## See also -- [Azure Service Bus](/azure/service-bus-messaging/) -- [.NET Aspire integrations](../fundamentals/integrations-overview.md) +- [Azure Service Bus](https://azure.microsoft.com/services/service-bus) +- [.NET Aspire integrations overview](../fundamentals/integrations-overview.md) +- [.NET Aspire Azure integrations overview](../azure/integrations-overview.md) - [.NET Aspire GitHub repo](https://github.com/dotnet/aspire) diff --git a/docs/snippets/azure/AppHost/Program.ConfigureServiceBusInfra.cs b/docs/snippets/azure/AppHost/Program.ConfigureServiceBusInfra.cs new file mode 100644 index 0000000000..02fe19f98a --- /dev/null +++ b/docs/snippets/azure/AppHost/Program.ConfigureServiceBusInfra.cs @@ -0,0 +1,23 @@ +using Azure.Provisioning.ServiceBus; + +internal static partial class Program +{ + public static void ConfigureServiceBusInfra(IDistributedApplicationBuilder builder) + { + // <configure> + builder.AddAzureServiceBus("service-bus") + .ConfigureInfrastructure(infra => + { + var serviceBusNamespace = infra.GetProvisionableResources() + .OfType<ServiceBusNamespace>() + .Single(); + + serviceBusNamespace.Sku = new ServiceBusSku + { + Tier = ServiceBusSkuTier.Premium + }; + serviceBusNamespace.Tags.Add("ExampleKey", "Example value"); + }); + // </configure> + } +} From 34d76ca2c236ebd795168ed26745409a8a821b7c Mon Sep 17 00:00:00 2001 From: David Pine <david.pine.7@gmail.com> Date: Wed, 8 Jan 2025 12:50:43 -0600 Subject: [PATCH 2/8] Fix tabs --- docs/messaging/azure-service-bus-integration.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/messaging/azure-service-bus-integration.md b/docs/messaging/azure-service-bus-integration.md index 50b3cc92b3..4efa51b2b8 100644 --- a/docs/messaging/azure-service-bus-integration.md +++ b/docs/messaging/azure-service-bus-integration.md @@ -32,6 +32,8 @@ dotnet add package Aspire.Hosting.Azure.ServiceBus Version="*" /> ``` +--- + For more information, see [dotnet add package](/dotnet/core/tools/dotnet-add-package) or [Manage package dependencies in .NET applications](/dotnet/core/tools/dependencies). ### Add Azure Service Bus resource From b97ac25dd5e6b2b79f2ad5ea367c6091e24b5437 Mon Sep 17 00:00:00 2001 From: David Pine <david.pine.7@gmail.com> Date: Wed, 8 Jan 2025 13:37:44 -0600 Subject: [PATCH 3/8] Fix a few more bits --- docs/messaging/azure-service-bus-integration.md | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/docs/messaging/azure-service-bus-integration.md b/docs/messaging/azure-service-bus-integration.md index 4efa51b2b8..2e7d3dd5b1 100644 --- a/docs/messaging/azure-service-bus-integration.md +++ b/docs/messaging/azure-service-bus-integration.md @@ -50,7 +50,8 @@ var serviceBus = builder.AddAzureServiceBus("messaging"); When you add an <xref:Aspire.Hosting.Azure.AzureServiceBusResource> to the app host, it exposes other useful APIs to add queues and topics. In other words, you must add an `AzureServiceBusResource` before adding any of the other Service Bus resources. -> [!IMPORTANT] When you call <xref:Aspire.Hosting.AzureServiceBusExtensions.AddAzureServiceBus*>, it implicitly calls <xref:Aspire.Hosting.AzureProvisionerExtensions.AddAzureProvisioning*>—which adds support for generating Azure resources dynamically during app startup. The app must configure the appropriate subscription and location. For more information, see [Configuration](../azure/local-provisioning.md#configuration). +> [!IMPORTANT] +> When you call <xref:Aspire.Hosting.AzureServiceBusExtensions.AddAzureServiceBus*>, it implicitly calls <xref:Aspire.Hosting.AzureProvisionerExtensions.AddAzureProvisioning*>—which adds support for generating Azure resources dynamically during app startup. The app must configure the appropriate subscription and location. For more information, see [Configuration](../azure/local-provisioning.md#configuration). #### Generated provisioning Bicep @@ -87,7 +88,7 @@ The preceding code: - The infra parameter is an instance of the <xref:Aspire.Hosting.Azure.AzureResourceInfrastructure> type. - The provisionable resources are retrieved by calling the <xref:Azure.Provisioning.Infrastructure.GetProvisionableResources> method. - The single <xref:Azure.Provisioning.ServiceBus.ServiceBusNamespace> is retrieved. - - The <xref:Azure.Provisioning.ServiceBus.ServiceBusNamespace.Sku?displayProperty=nameWithType> is assigned to a <xref:Azure.Provisioning.ServiceBus.ServiceBusSku.Premium?displayProperty=nameWithType>. + - The <xref:Azure.Provisioning.ServiceBus.ServiceBusNamespace.Sku?displayProperty=nameWithType> created with a <xref:Azure.Provisioning.ServiceBus.ServiceBusSkuTier.Premium?displayProperty=nameWithType> - A tag is added to the Service Bus namespace with a key of `ExampleKey` and a value of `Example value`. There are many more configuration options available to customize the Azure Service Bus resource. For more information, see <xref:Azure.Provisioning.ServiceBus>. For more information, see [Azure.Provisioning customization](../azure/integrations-overview.md#azureprovisioning-customization). @@ -166,8 +167,6 @@ var serviceBus = builder.AddAzureServiceBus("messaging") When you call `WithSubscription`, it configures your Service Bus resources to have a subscription named `subscription` on the topic named `topic`. The subscription 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 emulator resource To add an Azure Service Bus emulator resource, chain a call on an `<IResourceBuilder<AzureServiceBusResource>>` to the `RunAsEmulator` API: @@ -260,8 +259,6 @@ var serviceBus = builder.AddAzureServiceBus("messaging").RunAsEmulator( The preceding code retrieves the `UserConfig` node from the default configuration. It then updates the first queue's properties to set the `MaxDeliveryCount` to `5`, `RequiresDuplicateDetection` to `true`, and `DefaultMessageTimeToLive` to `2 hours`. ---> - ### Hosting integration health checks The Azure Service Bus hosting integration automatically adds a health check for the Service Bus resource. The health check verifies that the Service Bus is running and that a connection can be established to it. From 5365640af388d034284e24bdcc9b1977e5a444b7 Mon Sep 17 00:00:00 2001 From: David Pine <david.pine.7@gmail.com> Date: Wed, 8 Jan 2025 13:54:12 -0600 Subject: [PATCH 4/8] Remove subscription section and correct topics --- .../azure-service-bus-integration.md | 44 ++++++++++++++----- 1 file changed, 34 insertions(+), 10 deletions(-) diff --git a/docs/messaging/azure-service-bus-integration.md b/docs/messaging/azure-service-bus-integration.md index 2e7d3dd5b1..5cecbd4f51 100644 --- a/docs/messaging/azure-service-bus-integration.md +++ b/docs/messaging/azure-service-bus-integration.md @@ -122,9 +122,9 @@ The connection string is configured in the app host's configuration, typically u The dependent resource can access the injected connection string by calling the <xref:Microsoft.Extensions.Configuration.ConfigurationExtensions.GetConnectionString*> method, and passing the connection name as the parameter, in this case `"messaging"`. The `GetConnectionString` API is shorthand for `IConfiguration.GetSection("ConnectionStrings")[name]`. -### Add Azure Service Bus queue resource +### Add Azure Service Bus queue -To add an Azure Service Bus queue resource, chain a call on an `IResourceBuilder<AzureServiceBusResource>` to the <xref:Aspire.Hosting.AzureServiceBusExtensions.WithQueue*> API: +To add an Azure Service Bus queue, chain a call on an `IResourceBuilder<AzureServiceBusResource>` to the <xref:Aspire.Hosting.AzureServiceBusExtensions.WithQueue*> API: ```csharp var builder = DistributedApplication.CreateBuilder(args); @@ -137,9 +137,9 @@ var serviceBus = builder.AddAzureServiceBus("messaging") When you call `WithQueue`, 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). -### Add Azure Service Bus topic resource +### Add Azure Service Bus topic and subscription -To add an Azure Service Bus topic resource, chain a call on an `<IResourceBuilder<AzureServiceBusResource>>` to the <xref:Aspire.Hosting.AzureServiceBusExtensions.WithTopic*> API: +To add an Azure Service Bus topic, chain a call on an `<IResourceBuilder<AzureServiceBusResource>>` to the <xref:Aspire.Hosting.AzureServiceBusExtensions.WithTopic*> API: ```csharp var builder = DistributedApplication.CreateBuilder(args); @@ -150,22 +150,46 @@ var serviceBus = builder.AddAzureServiceBus("messaging") // After adding all resources, run the app... ``` -When you call `WithTopic`, it configures your Service Bus resources to have a topic named `topic`. The topic 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 `WithTopic`, it configures your Service Bus resources to have a topic named `topic`. The topic is created in the Service Bus namespace that's represented by the `AzureServiceBusResource` that you added earlier. -### Add Azure Service Bus subscription resource - -To add an Azure Service Bus subscription resource, chain a call on an `<IResourceBuilder<AzureServiceBusResource>>` to the <xref:Aspire.Hosting.AzureServiceBusExtensions.WithSubscription*> API: +To configure a subscription for the topic, use the overload <xref:Aspire.Hosting.AzureServiceBusExtensions.WithTopic*> API: ```csharp var builder = DistributedApplication.CreateBuilder(args); var serviceBus = builder.AddAzureServiceBus("messaging") - .WithSubscription("topic", "subscription"); + .WithTopic("topic", topic => + { + var subscription = new ServiceBusSubscription("sub1") + { + MaxDeliveryCount = 10, + Rules = + { + new ServiceBusRule("app-prop-filter-1") + { + CorrelationFilter = new() + { + ContentType = "application/text", + CorrelationId = "id1", + Subject = "subject1", + MessageId = "msgid1", + ReplyTo = "someQueue", + ReplyToSessionId = "sessionId", + SessionId = "session1", + SendTo = "xyz" + } + } + } + }; + topic.Subscriptions.Add(subscription); + }); // After adding all resources, run the app... ``` -When you call `WithSubscription`, it configures your Service Bus resources to have a subscription named `subscription` on the topic named `topic`. The subscription 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). +The preceding code not only adds a topic, but creates and configures a subscription named `sub1` for the topic. The subscription has a maximum delivery count of `10` and a rule named `app-prop-filter-1`. The rule is a correlation filter that filters messages based on the `ContentType`, `CorrelationId`, `Subject`, `MessageId`, `ReplyTo`, `ReplyToSessionId`, `SessionId`, and `SendTo` properties. + +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 emulator resource From 3fe588d94957eff824ecdd68c9fcfbff7cc5cc12 Mon Sep 17 00:00:00 2001 From: David Pine <david.pine.7@gmail.com> Date: Wed, 8 Jan 2025 14:03:48 -0600 Subject: [PATCH 5/8] Fix port info --- docs/messaging/azure-service-bus-integration.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/messaging/azure-service-bus-integration.md b/docs/messaging/azure-service-bus-integration.md index 5cecbd4f51..52451299b7 100644 --- a/docs/messaging/azure-service-bus-integration.md +++ b/docs/messaging/azure-service-bus-integration.md @@ -233,11 +233,11 @@ var serviceBus = builder.AddAzureServiceBus("messaging").RunAsEmulator( // After adding all resources, run the app... ``` -The preceding code configures the Service Bus emulator container's existing `emulator` endpoint to listen on port `5672`. The Service Bus emulator container's port is mapped to the host port as shown in the following table: +The preceding code configures the Service Bus emulator container's existing `emulator` endpoint to listen on port `7777`. The Service Bus emulator container's port is mapped to the host port as shown in the following table: | Endpoint name | Port mapping (`container:host`) | -|--------------:|---------------------------------| -| `https` | `8081:5672` | +|---------------|---------------------------------| +| `emulator` | `5672:7777` | ##### Configure Service Bus emulator container JSON configuration From 5b7313886390ada29d6cf325975ebc98d40f1765 Mon Sep 17 00:00:00 2001 From: David Pine <david.pine@microsoft.com> Date: Mon, 10 Feb 2025 13:18:00 -0600 Subject: [PATCH 6/8] Apply suggestions from code review --- docs/messaging/azure-service-bus-integration.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/messaging/azure-service-bus-integration.md b/docs/messaging/azure-service-bus-integration.md index 52451299b7..471a95ef97 100644 --- a/docs/messaging/azure-service-bus-integration.md +++ b/docs/messaging/azure-service-bus-integration.md @@ -208,7 +208,7 @@ When you call `RunAsEmulator`, it configures your Service Bus resources to run l #### Configure Service Bus emulator container -There are various configurations available to container resources, for example, you can configure the container's ports or providing a wholistic JSON configuration which overrides everything. +There are various configurations available for container resources, for example, you can configure the container's ports or providing a wholistic JSON configuration which overrides everything. ##### Configure Service Bus emulator container host port From 9d95dca447d79178de0b3bde1874a92befbe3604 Mon Sep 17 00:00:00 2001 From: David Pine <david.pine@microsoft.com> Date: Mon, 10 Feb 2025 13:28:33 -0600 Subject: [PATCH 7/8] Apply suggestions from code review --- docs/messaging/azure-service-bus-integration.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/messaging/azure-service-bus-integration.md b/docs/messaging/azure-service-bus-integration.md index 471a95ef97..6197e99fb7 100644 --- a/docs/messaging/azure-service-bus-integration.md +++ b/docs/messaging/azure-service-bus-integration.md @@ -287,7 +287,7 @@ The preceding code retrieves the `UserConfig` node from the default configuratio The Azure Service Bus hosting integration automatically adds a health check for the Service Bus resource. The health check verifies that the Service Bus is running and that a connection can be established to it. -The hosting integration relies on the [📦 AspNetCore.HealthChecks.ServiceBus](https://www.nuget.org/packages/AspNetCore.HealthChecks.ServiceBus) NuGet package. +The hosting integration relies on the [📦 AspNetCore.HealthChecks.AzureServiceBus](https://www.nuget.org/packages/AspNetCore.HealthChecks.AzureServiceBus) NuGet package. ## Client integration From 617122a516b4439bda532d3bb64e78d46a1b089c Mon Sep 17 00:00:00 2001 From: David Pine <david.pine@microsoft.com> Date: Tue, 11 Feb 2025 08:43:49 -0600 Subject: [PATCH 8/8] Apply suggestions from code review --- docs/messaging/azure-service-bus-integration.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/messaging/azure-service-bus-integration.md b/docs/messaging/azure-service-bus-integration.md index 6197e99fb7..c46e2e32a0 100644 --- a/docs/messaging/azure-service-bus-integration.md +++ b/docs/messaging/azure-service-bus-integration.md @@ -487,7 +487,7 @@ Azure Service Bus tracing is currently in preview, so you must set the experimen AppContext.SetSwitch("Azure.Experimental.EnableActivitySource", true); ``` -For more information, see [Azure Service Bus SDK observability: Trace attributes](/azure/service-bus/nosql/sdk-observability?tabs=dotnet#trace-attributes). +For more information, see [Azure Service Bus: Distributed tracing and correlation through Service Bus messaging](/azure/service-bus-messaging/service-bus-end-to-end-tracing). #### Metrics