From 26f27b91dc02f225c3d9edbf133dadaa55f45a86 Mon Sep 17 00:00:00 2001 From: Alex Wolf Date: Tue, 8 Aug 2023 15:04:46 -0400 Subject: [PATCH 01/24] initial commit --- docs/azure/sdk/dependency-injection.md | 14 ++++ .../Directory.Packages.props | 15 ++++ .../HostApplicationBuilder.csproj | 18 +++++ .../HostApplicationBuilder/Program.cs | 33 +++++++++ .../HostBuilder/HostBuilder.csproj | 18 +++++ .../HostBuilder/Program.cs | 39 +++++++++++ .../WebApplicationBuilder/Program.cs | 70 +++++++++++++++++++ .../WebApplicationBuilder.csproj | 19 +++++ 8 files changed, 226 insertions(+) create mode 100644 docs/azure/sdk/snippets/dependency-injection/Directory.Packages.props create mode 100644 docs/azure/sdk/snippets/dependency-injection/HostApplicationBuilder/HostApplicationBuilder.csproj create mode 100644 docs/azure/sdk/snippets/dependency-injection/HostApplicationBuilder/Program.cs create mode 100644 docs/azure/sdk/snippets/dependency-injection/HostBuilder/HostBuilder.csproj create mode 100644 docs/azure/sdk/snippets/dependency-injection/HostBuilder/Program.cs create mode 100644 docs/azure/sdk/snippets/dependency-injection/WebApplicationBuilder/Program.cs create mode 100644 docs/azure/sdk/snippets/dependency-injection/WebApplicationBuilder/WebApplicationBuilder.csproj diff --git a/docs/azure/sdk/dependency-injection.md b/docs/azure/sdk/dependency-injection.md index 824654783f63d..651b2bb3aad23 100644 --- a/docs/azure/sdk/dependency-injection.md +++ b/docs/azure/sdk/dependency-injection.md @@ -23,11 +23,19 @@ dotnet add package Microsoft.Extensions.Azure dotnet add package Azure.Identity dotnet add package Azure.Security.KeyVault.Secrets dotnet add package Azure.Storage.Blobs +dotnet add package Azure.Storage.ServiceBus ``` +<<<<<<< Updated upstream ## Register client In the _Program.cs_ file, register a client for each service: +======= +## Register clients and subclients + +A service client is the entry point to the API for an Azure service – from it, library users can invoke all operations the service provides and can easily implement the most common scenarios. In the *Program.cs* file, invoke the extension method to register a client for each service. +Where it will simplify an API's design, groups of service calls can be organized around smaller subclient types. The following code samples provide guidance on application builders from the `Microsoft.AspNetCore.Builder` and `Microsoft.Extensions.Hosting` namespaces. +>>>>>>> Stashed changes ```csharp builder.Services.AddAzureClients(clientBuilder => @@ -47,8 +55,14 @@ builder.Services.AddControllers(); In the preceding code: +<<<<<<< Updated upstream * You specify the `Uri`-typed `keyVaultUrl` and `storageUrl` variables. The [Store configuration separately from code](#store-configuration-separately-from-code) section shows how you can avoid specifying the URLs explicitly. * is used for authentication. `DefaultAzureCredential` chooses the best authentication mechanism based on your environment, allowing you to move your app seamlessly from development to production with no code changes. +======= +* Key Vault Secrets and Blob Storage clients are registered using and , respectively. The `Uri`-typed arguments are passed. To avoid specifying these URLs explicitly, see the [Store configuration separately from code](#store-configuration-separately-from-code) section. +* is used to satisfy the `TokenCredential` argument requirement for each registered client. When one of the clients is created, `DefaultAzureCredential` is used to authenticate. +* Service Bus subclients are registered for each queue on the service using the subclient type and a corresponding options type. +>>>>>>> Stashed changes ## Use the registered clients diff --git a/docs/azure/sdk/snippets/dependency-injection/Directory.Packages.props b/docs/azure/sdk/snippets/dependency-injection/Directory.Packages.props new file mode 100644 index 0000000000000..0dc07aa60cabe --- /dev/null +++ b/docs/azure/sdk/snippets/dependency-injection/Directory.Packages.props @@ -0,0 +1,15 @@ + + + true + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/azure/sdk/snippets/dependency-injection/HostApplicationBuilder/HostApplicationBuilder.csproj b/docs/azure/sdk/snippets/dependency-injection/HostApplicationBuilder/HostApplicationBuilder.csproj new file mode 100644 index 0000000000000..54b28c586b873 --- /dev/null +++ b/docs/azure/sdk/snippets/dependency-injection/HostApplicationBuilder/HostApplicationBuilder.csproj @@ -0,0 +1,18 @@ + + + + Exe + net7.0 + enable + enable + + + + + + + + + + + diff --git a/docs/azure/sdk/snippets/dependency-injection/HostApplicationBuilder/Program.cs b/docs/azure/sdk/snippets/dependency-injection/HostApplicationBuilder/Program.cs new file mode 100644 index 0000000000000..5a3e6290c77ff --- /dev/null +++ b/docs/azure/sdk/snippets/dependency-injection/HostApplicationBuilder/Program.cs @@ -0,0 +1,33 @@ +using Azure.Identity; +using Azure.Messaging.ServiceBus; +using Azure.Messaging.ServiceBus.Administration; +using Microsoft.Extensions.Azure; +using Microsoft.Extensions.Hosting; + +HostApplicationBuilder builder = Host.CreateApplicationBuilder(args); + +builder.Services.AddAzureClients(async clientBuilder => +{ + // Register clients for each service + var credential = new DefaultAzureCredential(); + + clientBuilder.AddSecretClient(new Uri("")); + clientBuilder.AddBlobServiceClient(new Uri("")); + clientBuilder.AddServiceBusClient(".servicebus.windows.net"); + clientBuilder.UseCredential(new DefaultAzureCredential()); + + // Register a subclient for each Service Bus Queue + var admin = new ServiceBusAdministrationClient( + ".servicebus.windows.net", credential); + + await foreach (var queue in admin.GetQueuesAsync()) + { + clientBuilder.AddClient((_, _, provider) => + provider.GetService()! + .CreateSender(queue.Name) + ).WithName(queue.Name); + } +}); + +using IHost host = builder.Build(); +await host.RunAsync(); diff --git a/docs/azure/sdk/snippets/dependency-injection/HostBuilder/HostBuilder.csproj b/docs/azure/sdk/snippets/dependency-injection/HostBuilder/HostBuilder.csproj new file mode 100644 index 0000000000000..393da41132e87 --- /dev/null +++ b/docs/azure/sdk/snippets/dependency-injection/HostBuilder/HostBuilder.csproj @@ -0,0 +1,18 @@ + + + + net7.0 + enable + enable + dotnet-HostBuilder-3f144e50-3cf7-463d-b3e7-33f5e9a62474 + + + + + + + + + + + diff --git a/docs/azure/sdk/snippets/dependency-injection/HostBuilder/Program.cs b/docs/azure/sdk/snippets/dependency-injection/HostBuilder/Program.cs new file mode 100644 index 0000000000000..9379bccb7cec0 --- /dev/null +++ b/docs/azure/sdk/snippets/dependency-injection/HostBuilder/Program.cs @@ -0,0 +1,39 @@ +using HostBuilder; +#region snippet_HostBuilder +using Azure.Identity; +using Microsoft.Extensions.Azure; +using Azure.Messaging.ServiceBus; +using Azure.Messaging.ServiceBus.Administration; +using Microsoft.Identity.Client.Platforms.Features.DesktopOs.Kerberos; + +IHost host = Host.CreateDefaultBuilder(args) + .ConfigureServices(services => + { + services.AddHostedService(); + services.AddAzureClients(async clientBuilder => + { + // Register clients for each service + var credential = new DefaultAzureCredential(); + + clientBuilder.AddSecretClient(new Uri("")); + clientBuilder.AddBlobServiceClient(new Uri("")); + clientBuilder.AddServiceBusClient(".servicebus.windows.net"); + clientBuilder.UseCredential(new DefaultAzureCredential()); + + // Register a subclient for each Service Bus Queue + var admin = new ServiceBusAdministrationClient( + ".servicebus.windows.net", credential); + + await foreach (var queue in admin.GetQueuesAsync()) + { + clientBuilder.AddClient((_, _, provider) => + provider.GetService()! + .CreateSender(queue.Name) + ).WithName(queue.Name); + } + }); + }) + .Build(); + +await host.RunAsync(); +#endregion snippet_HostBuilder diff --git a/docs/azure/sdk/snippets/dependency-injection/WebApplicationBuilder/Program.cs b/docs/azure/sdk/snippets/dependency-injection/WebApplicationBuilder/Program.cs new file mode 100644 index 0000000000000..63ddc73f3c617 --- /dev/null +++ b/docs/azure/sdk/snippets/dependency-injection/WebApplicationBuilder/Program.cs @@ -0,0 +1,70 @@ +#region snippet_WebApplicationBuilder +using Azure.Identity; +using Azure.Messaging.ServiceBus; +using Azure.Messaging.ServiceBus.Administration; +using Azure.Storage.Blobs; +using Microsoft.Extensions.Azure; + +WebApplicationBuilder builder = WebApplication.CreateBuilder(args); + +#region snippet_WebApplicationBuilder +builder.Services.AddAzureClients(async clientBuilder => +{ + // Register clients for each service + var credential = new DefaultAzureCredential(); + + clientBuilder.AddSecretClient(new Uri("")); + clientBuilder.AddBlobServiceClient(new Uri("")); + clientBuilder.AddServiceBusClient(".servicebus.windows.net"); + clientBuilder.UseCredential(new DefaultAzureCredential()); + + // Register a subclient for each Service Bus Queue + var admin = new ServiceBusAdministrationClient( + ".servicebus.windows.net", credential); + + await foreach (var queue in admin.GetQueuesAsync()) + { + clientBuilder.AddClient((_, _, provider) => + provider.GetService()! + .CreateSender(queue.Name) + ).WithName(queue.Name); + } +}); + +WebApplication app = builder.Build(); +#endregion snippet_WebApplicationBuilder + +if (app.Environment.IsDevelopment()) +{ + app.UseSwagger(); + app.UseSwaggerUI(); +} + +app.UseHttpsRedirection(); + +string[] summaries = new[] +{ + "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" +}; + +app.MapGet("/weatherforecast", () => +{ + WeatherForecast[] forecast = Enumerable.Range(1, 5).Select(index => + new WeatherForecast + ( + DateOnly.FromDateTime(DateTime.Now.AddDays(index)), + Random.Shared.Next(-20, 55), + summaries[Random.Shared.Next(summaries.Length)] + )) + .ToArray(); + return forecast; +}) +.WithName("GetWeatherForecast") +.WithOpenApi(); + +await app.RunAsync(); + +internal record WeatherForecast(DateOnly Date, int TemperatureC, string? Summary) +{ + public int TemperatureF => 32 + (int)(TemperatureC / 0.5556); +} diff --git a/docs/azure/sdk/snippets/dependency-injection/WebApplicationBuilder/WebApplicationBuilder.csproj b/docs/azure/sdk/snippets/dependency-injection/WebApplicationBuilder/WebApplicationBuilder.csproj new file mode 100644 index 0000000000000..87ea3e207d5ae --- /dev/null +++ b/docs/azure/sdk/snippets/dependency-injection/WebApplicationBuilder/WebApplicationBuilder.csproj @@ -0,0 +1,19 @@ + + + + net7.0 + enable + enable + + + + + + + + + + + + + From 1b917a9e26cd20c027efd43cbb7eed3f8630edfa Mon Sep 17 00:00:00 2001 From: Alex Wolf Date: Wed, 9 Aug 2023 13:24:37 -0400 Subject: [PATCH 02/24] service bus integration --- docs/azure/sdk/dependency-injection.md | 197 ++++++++++++------ .../HostApplicationBuilder/Program.cs | 57 +++-- .../HostBuilder/Program.cs | 43 ++-- .../WebApplicationBuilder/Program.cs | 39 ++-- 4 files changed, 222 insertions(+), 114 deletions(-) diff --git a/docs/azure/sdk/dependency-injection.md b/docs/azure/sdk/dependency-injection.md index 651b2bb3aad23..6b5072f05fcd3 100644 --- a/docs/azure/sdk/dependency-injection.md +++ b/docs/azure/sdk/dependency-injection.md @@ -3,70 +3,68 @@ title: Dependency injection with the Azure SDK for .NET description: Learn how to use dependency injection with the Azure SDK for .NET client libraries. ms.topic: how-to ms.custom: devx-track-dotnet, engagement-fy23 -ms.date: 2/28/2023 +ms.date: 07/21/2023 --- # Dependency injection with the Azure SDK for .NET -This article demonstrates how to register Azure service clients from the [latest Azure SDKs for .NET](https://azure.github.io/azure-sdk/releases/latest/index.html#net) for [dependency injection in an ASP.NET Core app](/aspnet/core/fundamentals/dependency-injection). Every ASP.NET Core app starts up by using the instructions provided in the _Program.cs_ file. +This article demonstrates how to register Azure service clients from the [latest Azure client libraries for .NET](https://azure.github.io/azure-sdk/releases/latest/index.html#net) for [dependency injection in a .NET app](/dotnet/core/extensions/dependency-injection). Every modern .NET app starts up by using the instructions provided in a *Program.cs* file. -To configure the service clients, first add the following NuGet packages to your project: +## Install packages -- [Microsoft.Extensions.Azure](https://github.com/Azure/azure-sdk-for-net/blob/master/sdk/extensions/Microsoft.Extensions.Azure/README.md) -- [Azure.Identity](https://github.com/Azure/azure-sdk-for-net/blob/master/sdk/identity/Azure.Identity/README.md) -- The `Azure.*` package you'd like to use. +To register and configure service clients from an [`Azure.`-prefixed package](/dotnet/azure/sdk/packages#libraries-using-azurecore): -The sample code in this article uses Key Vault secrets and Blob Storage for demonstration purposes. +1. Install the [Microsoft.Extensions.Azure](https://www.nuget.org/packages/Microsoft.Extensions.Azure) package in your project: + + ```dotnetcli + dotnet add package Microsoft.Extensions.Azure + ``` + +1. Install the [Azure.Identity](https://www.nuget.org/packages/Azure.Identity) package to configure a `TokenCredential` type to use for authenticating all registered clients that accept such a type: + + ```dotnetcli + dotnet add package Azure.Identity + ``` + +For demonstration purposes, the sample code in this article uses the Key Vault Secrets and Blob Storage libraries. Install the following packages to follow along: ```dotnetcli -dotnet add package Microsoft.Extensions.Azure -dotnet add package Azure.Identity dotnet add package Azure.Security.KeyVault.Secrets dotnet add package Azure.Storage.Blobs dotnet add package Azure.Storage.ServiceBus ``` -<<<<<<< Updated upstream -## Register client - -In the _Program.cs_ file, register a client for each service: -======= ## Register clients and subclients A service client is the entry point to the API for an Azure service – from it, library users can invoke all operations the service provides and can easily implement the most common scenarios. In the *Program.cs* file, invoke the extension method to register a client for each service. -Where it will simplify an API's design, groups of service calls can be organized around smaller subclient types. The following code samples provide guidance on application builders from the `Microsoft.AspNetCore.Builder` and `Microsoft.Extensions.Hosting` namespaces. ->>>>>>> Stashed changes -```csharp -builder.Services.AddAzureClients(clientBuilder => -{ - // Add a KeyVault client - clientBuilder.AddSecretClient(keyVaultUrl); +Where it will simplify an API's design, groups of service calls can be organized around smaller subclient types. For example, `ServiceBusClient` can register additional `ServiceBusSender` clients to simplify working with queues. - // Add a Storage account client - clientBuilder.AddBlobServiceClient(storageUrl); +The following code samples provide guidance on application builders from the `Microsoft.AspNetCore.Builder` and `Microsoft.Extensions.Hosting` namespaces. - // Use DefaultAzureCredential by default - clientBuilder.UseCredential(new DefaultAzureCredential()); -}); +### [WebApplicationBuilder](#tab/web-app-builder) -builder.Services.AddControllers(); -``` +:::code language="csharp" source="snippets/dependency-injection/WebApplicationBuilder/Program.cs" id="snippet_WebApplicationBuilder" highlight="14-24"::: + +### [HostApplicationBuilder](#tab/host-app-builder) + +:::code language="csharp" source="snippets/dependency-injection/HostApplicationBuilder/Program.cs" highlight="12-30"::: + +### [HostBuilder](#tab/host-builder) + +:::code language="csharp" source="snippets/dependency-injection/HostBuilder/Program.cs" id="snippet_HostBuilder" highlight="12-27"::: + +--- In the preceding code: -<<<<<<< Updated upstream -* You specify the `Uri`-typed `keyVaultUrl` and `storageUrl` variables. The [Store configuration separately from code](#store-configuration-separately-from-code) section shows how you can avoid specifying the URLs explicitly. -* is used for authentication. `DefaultAzureCredential` chooses the best authentication mechanism based on your environment, allowing you to move your app seamlessly from development to production with no code changes. -======= -* Key Vault Secrets and Blob Storage clients are registered using and , respectively. The `Uri`-typed arguments are passed. To avoid specifying these URLs explicitly, see the [Store configuration separately from code](#store-configuration-separately-from-code) section. +* Key Vault Secrets, Blob Storage and Service Bus clients are registered using and , respectively. The `Uri`-typed arguments are passed. To avoid specifying these URLs explicitly, see the [Store configuration separately from code](#store-configuration-separately-from-code) section. * is used to satisfy the `TokenCredential` argument requirement for each registered client. When one of the clients is created, `DefaultAzureCredential` is used to authenticate. -* Service Bus subclients are registered for each queue on the service using the subclient type and a corresponding options type. ->>>>>>> Stashed changes +* Service Bus subclients are registered for each queue on the service using the subclient and corresponding options types. ## Use the registered clients -With the clients registered in the `AddAzureClients`, you can now use them: +With the clients registered, as described in the [Register clients](#register-clients) section, you can now use them. In the following example, [constructor injection](/dotnet/core/extensions/dependency-injection#constructor-injection-behavior) is used to obtain the Blob Storage client in an ASP.NET Core API controller: ```csharp [ApiController] @@ -80,16 +78,18 @@ public class MyApiController : ControllerBase _blobServiceClient = blobServiceClient; } - // Get a list of all the blobs in the demo container [HttpGet] public async Task> Get() { - var containerClient = _blobServiceClient.GetBlobContainerClient("demo"); + BlobContainerClient containerClient = + _blobServiceClient.GetBlobContainerClient("demo"); var results = new List(); + await foreach (BlobItem blob in containerClient.GetBlobsAsync()) { results.Add(blob.Name); } + return results.ToArray(); } } @@ -97,7 +97,7 @@ public class MyApiController : ControllerBase ## Store configuration separately from code -In the [Register client](#register-client) section, you explicitly specify the `keyVaultUrl` and `storageUrl` variables. This approach could cause problems when you run code against different environments during development and production. The .NET team suggests [storing such configurations in environment-dependent JSON files](../../core/extensions/configuration-providers.md#json-configuration-provider). For example, you can have an _appsettings.Development.json_ file containing development environment settings. Another _appsettings.Production.json_ file would contain production environment settings, and so on. The file format is: +In the [Register clients](#register-clients) section, you explicitly passed the `Uri`-typed variables to the client constructors. This approach could cause problems when you run code against different environments during development and production. The .NET team suggests [storing such configurations in environment-dependent JSON files](../../core/extensions/configuration-providers.md#json-configuration-provider). For example, you can have an *appsettings.Development.json* file containing development environment settings. Another *appsettings.Production.json* file would contain production environment settings, and so on. The file format is: ```json { @@ -116,47 +116,114 @@ In the [Register client](#register-client) section, you explicitly specify the ` }, "Storage": { "ServiceUri": "https://mydemoaccount.storage.windows.net" + }, + "ServiceBus": { + "ServiceUri": "https://mydemoaccount.storage.windows.net" } } ``` -You can add any options from into the JSON file's `AzureDefaults` section. One of the options is the retry policy. For more information, see [Configure a new retry policy](#configure-a-new-retry-policy). +You can add any properties from the class into the JSON file. The settings in the JSON configuration file can be retrieved using . + +### [WebApplicationBuilder](#tab/web-app-builder) + +```csharp +builder.Services.AddAzureClients(clientBuilder => +{ + clientBuilder.AddSecretClient( + builder.Configuration.GetSection("KeyVault")); + + clientBuilder.AddBlobServiceClient( + builder.Configuration.GetSection("Storage")); -Since the `Configuration` object is a member of the `builder` instance, you can configure secrets: + clientBuilder.AddServiceBusClient( + builder.Configuration.GetSection("ServiceBus")); + + clientBuilder.UseCredential(new DefaultAzureCredential()); + + // Set up any default settings + clientBuilder.ConfigureDefaults( + builder.Configuration.GetSection("AzureDefaults")); +}); +``` + +### [HostApplicationBuilder](#tab/host-app-builder) ```csharp builder.Services.AddAzureClients(clientBuilder => { - // Add a KeyVault client - clientBuilder.AddSecretClient(builder.Configuration.GetSection("KeyVault")); + clientBuilder.AddSecretClient( + builder.Configuration.GetSection("KeyVault")); + + clientBuilder.AddBlobServiceClient( + builder.Configuration.GetSection("Storage")); - // Add a storage account client - clientBuilder.AddBlobServiceClient(builder.Configuration.GetSection("Storage")); + clientBuilder.AddServiceBusClient( + builder.Configuration.GetSection("ServiceBus")); - // Use DefaultAzureCredential by default clientBuilder.UseCredential(new DefaultAzureCredential()); // Set up any default settings - clientBuilder.ConfigureDefaults(builder.Configuration.GetSection("AzureDefaults")); + clientBuilder.ConfigureDefaults( + builder.Configuration.GetSection("AzureDefaults")); }); +``` + +### [HostBuilder](#tab/host-builder) -builder.Services.AddControllers(); +```csharp +IHost host = Host.CreateDefaultBuilder(args) + .ConfigureServices((hostContext, services) => + { + services.AddHostedService(); + services.AddAzureClients(clientBuilder => + { + clientBuilder.AddSecretClient( + hostContext.Configuration.GetSection("KeyVault")); + + clientBuilder.AddBlobServiceClient( + hostContext.Configuration.GetSection("Storage")); + + clientBuilder.AddServiceBusClient( + hostContext.Configuration.GetSection("ServiceBus")); + + clientBuilder.UseCredential(new DefaultAzureCredential()); + + // Set up any default settings + clientBuilder.ConfigureDefaults( + hostContext.Configuration.GetSection("AzureDefaults")); + }); + }) + .Build(); ``` +--- + +In the preceding JSON sample: + +* The top-level key names, `AzureDefaults`, `KeyVault`, and `Storage`, are arbitrary. All other key names hold significance, and JSON serialization is performed in a case-insensitive manner. +* The `AzureDefaults.Retry` object literal: + * Represents the [retry policy configuration settings](#configure-a-new-retry-policy). + * Corresponds to the property. Within that object literal, you find the `MaxRetries` key, which corresponds to the property. +* The `KeyVault:VaultUri` and `Storage:ServiceUri` key values map to the `Uri`-typed arguments of the and constructor overloads, respectively. The `TokenCredential` variants of the constructors are used because a default `TokenCredential` is set via the method call. + ## Configure multiple service clients with different names -Assume you have two storage accounts: one for private information and one for public information. Your app transfers data from the public to private storage account after some operation. You need to have two storage service clients. To set up these clients in the _Program.cs_ file: +Imagine you have two storage accounts: one for private information and another for public information. Your app transfers data from the public to the private storage account after some operation. You need to have two storage service clients. To differentiate those two clients, use the extension method: ```csharp builder.Services.AddAzureClients(clientBuilder => { - clientBuilder.AddBlobServiceClient(builder.Configuration.GetSection("PublicStorage")); - clientBuilder.AddBlobServiceClient(builder.Configuration.GetSection("PrivateStorage")) + clientBuilder.AddBlobServiceClient( + builder.Configuration.GetSection("PublicStorage")); + + clientBuilder.AddBlobServiceClient( + builder.Configuration.GetSection("PrivateStorage")) .WithName("PrivateStorage"); }); ``` -In your controller, you can access the named service clients using : +Using an ASP.NET Core controller as an example, access the named service client using the interface: ```csharp public class HomeController : Controller @@ -178,7 +245,7 @@ The unnamed service client is still available in the same way as before. Named c ## Configure a new retry policy -At some point, you might want to change the default settings for a service client. You may want different retry settings or to use a different service API version, for example. You can set the retry settings globally or on a per-service basis. Assume you have the following _appsettings.json_ file: +At some point, you may want to change the default settings for a service client. For example, you may want different retry settings or to use a different service API version. You can set the retry settings globally or on a per-service basis. Assume you have the following *appsettings.json* file in your ASP.NET Core project: ```json { @@ -199,24 +266,28 @@ At some point, you might want to change the default settings for a service clien } ``` -You could change the retry policy depending on your needs like so: +You can change the retry policy to suit your needs like so: ```csharp builder.Services.AddAzureClients(clientBuilder => { // Establish the global defaults - clientBuilder.ConfigureDefaults(builder.Configuration.GetSection("AzureDefaults")); + clientBuilder.ConfigureDefaults( + builder.Configuration.GetSection("AzureDefaults")); clientBuilder.UseCredential(new DefaultAzureCredential()); // A Key Vault Secrets client using the global defaults - clientBuilder.AddSecretClient(builder.Configuration.GetSection("KeyVault")); + clientBuilder.AddSecretClient( + builder.Configuration.GetSection("KeyVault")); - // A Storage client with a custom retry policy - clientBuilder.AddBlobServiceClient(builder.Configuration.GetSection("Storage")) + // A Blob Storage client with a custom retry policy + clientBuilder.AddBlobServiceClient( + builder.Configuration.GetSection("Storage")) .ConfigureOptions(options => options.Retry.MaxRetries = 10); // A named storage client with a different custom retry policy - clientBuilder.AddBlobServiceClient(builder.Configuration.GetSection("CustomStorage")) + clientBuilder.AddBlobServiceClient( + builder.Configuration.GetSection("CustomStorage")) .WithName("CustomStorage") .ConfigureOptions(options => { @@ -227,7 +298,7 @@ builder.Services.AddAzureClients(clientBuilder => }); ``` -You can also place policy overrides in the _appsettings.json_ file: +You can also place retry policy overrides in the *appsettings.json* file: ```json { @@ -242,6 +313,6 @@ You can also place policy overrides in the _appsettings.json_ file: ## See also -- [Dependency injection in .NET](../../core/extensions/dependency-injection.md) -- [Configuration in .NET](../../core/extensions/configuration.md) -- [Configuration in ASP.NET Core](/aspnet/core/fundamentals/configuration) +* [Dependency injection in ASP.NET Core](/aspnet/core/fundamentals/dependency-injection) +* [Configuration in .NET](/dotnet/core/extensions/configuration) +* [Configuration in ASP.NET Core](/aspnet/core/fundamentals/configuration) diff --git a/docs/azure/sdk/snippets/dependency-injection/HostApplicationBuilder/Program.cs b/docs/azure/sdk/snippets/dependency-injection/HostApplicationBuilder/Program.cs index 5a3e6290c77ff..f1968f90795eb 100644 --- a/docs/azure/sdk/snippets/dependency-injection/HostApplicationBuilder/Program.cs +++ b/docs/azure/sdk/snippets/dependency-injection/HostApplicationBuilder/Program.cs @@ -4,30 +4,47 @@ using Microsoft.Extensions.Azure; using Microsoft.Extensions.Hosting; -HostApplicationBuilder builder = Host.CreateApplicationBuilder(args); +var queueNames = await GetQueueNames(); -builder.Services.AddAzureClients(async clientBuilder => -{ - // Register clients for each service - var credential = new DefaultAzureCredential(); +IHost host = Host.CreateDefaultBuilder(args) + .ConfigureServices(services => + { + services.AddAzureClients(clientBuilder => + { + // Register clients for each service + clientBuilder.AddSecretClient(new Uri("")); + clientBuilder.AddBlobServiceClient(new Uri("")); + clientBuilder.AddServiceBusClient(".servicebus.windows.net"); + clientBuilder.UseCredential(new DefaultAzureCredential()); + + // Register subclients for Service Bus + foreach (var queueName in queueNames) + { + clientBuilder.AddClient((_, _, provider) => + provider.GetService(typeof(ServiceBusClient)) switch + { + ServiceBusClient client => client.CreateSender(queueName), + _ => throw new InvalidOperationException("Unable to create ServiceBusClient") + }).WithName(queueName); + } + }); + }).Build(); - clientBuilder.AddSecretClient(new Uri("")); - clientBuilder.AddBlobServiceClient(new Uri("")); - clientBuilder.AddServiceBusClient(".servicebus.windows.net"); - clientBuilder.UseCredential(new DefaultAzureCredential()); +await host.RunAsync(); - // Register a subclient for each Service Bus Queue - var admin = new ServiceBusAdministrationClient( - ".servicebus.windows.net", credential); +async Task> GetQueueNames() +{ + // Query the available queues for the Service Bus namespace. + var adminClient = new ServiceBusAdministrationClient + (".servicebus.windows.net", new DefaultAzureCredential()); + var queueNames = new List(); - await foreach (var queue in admin.GetQueuesAsync()) + // Because the result is async, they need to be captured to a standard list to avoid async + // calls when registering. Failure to do so results in an error with the services collection. + await foreach (var queue in adminClient.GetQueuesAsync()) { - clientBuilder.AddClient((_, _, provider) => - provider.GetService()! - .CreateSender(queue.Name) - ).WithName(queue.Name); + queueNames.Add(queue.Name); } -}); -using IHost host = builder.Build(); -await host.RunAsync(); + return queueNames; +} diff --git a/docs/azure/sdk/snippets/dependency-injection/HostBuilder/Program.cs b/docs/azure/sdk/snippets/dependency-injection/HostBuilder/Program.cs index 9379bccb7cec0..3740a80be0379 100644 --- a/docs/azure/sdk/snippets/dependency-injection/HostBuilder/Program.cs +++ b/docs/azure/sdk/snippets/dependency-injection/HostBuilder/Program.cs @@ -1,39 +1,48 @@ -using HostBuilder; -#region snippet_HostBuilder +#region snippet_HostBuilder using Azure.Identity; -using Microsoft.Extensions.Azure; using Azure.Messaging.ServiceBus; using Azure.Messaging.ServiceBus.Administration; -using Microsoft.Identity.Client.Platforms.Features.DesktopOs.Kerberos; +using Microsoft.Extensions.Azure; + +var queueNames = await GetQueueNames(); IHost host = Host.CreateDefaultBuilder(args) .ConfigureServices(services => { - services.AddHostedService(); - services.AddAzureClients(async clientBuilder => + services.AddAzureClients(clientBuilder => { // Register clients for each service - var credential = new DefaultAzureCredential(); - clientBuilder.AddSecretClient(new Uri("")); clientBuilder.AddBlobServiceClient(new Uri("")); clientBuilder.AddServiceBusClient(".servicebus.windows.net"); clientBuilder.UseCredential(new DefaultAzureCredential()); // Register a subclient for each Service Bus Queue - var admin = new ServiceBusAdministrationClient( - ".servicebus.windows.net", credential); - - await foreach (var queue in admin.GetQueuesAsync()) + foreach (var queue in queueNames) { clientBuilder.AddClient((_, _, provider) => - provider.GetService()! - .CreateSender(queue.Name) - ).WithName(queue.Name); + provider.GetService()!.CreateSender(queue) + ).WithName(queue); } }); - }) - .Build(); + }).Build(); await host.RunAsync(); + +async Task> GetQueueNames() +{ + // Query the available queues for the Service Bus namespace. + var adminClient = new ServiceBusAdministrationClient + (".servicebus.windows.net", new DefaultAzureCredential()); + var queueNames = new List(); + + // Because the result is async, they need to be captured to a standard list to avoid async + // calls when registering. Failure to do so results in an error with the services collection. + await foreach (var queue in adminClient.GetQueuesAsync()) + { + queueNames.Add(queue.Name); + } + + return queueNames; +} #endregion snippet_HostBuilder diff --git a/docs/azure/sdk/snippets/dependency-injection/WebApplicationBuilder/Program.cs b/docs/azure/sdk/snippets/dependency-injection/WebApplicationBuilder/Program.cs index 63ddc73f3c617..cb53cc28e1ef1 100644 --- a/docs/azure/sdk/snippets/dependency-injection/WebApplicationBuilder/Program.cs +++ b/docs/azure/sdk/snippets/dependency-injection/WebApplicationBuilder/Program.cs @@ -2,37 +2,48 @@ using Azure.Identity; using Azure.Messaging.ServiceBus; using Azure.Messaging.ServiceBus.Administration; -using Azure.Storage.Blobs; using Microsoft.Extensions.Azure; WebApplicationBuilder builder = WebApplication.CreateBuilder(args); -#region snippet_WebApplicationBuilder -builder.Services.AddAzureClients(async clientBuilder => +var queueNames = await GetQueueNames(); + +builder.Services.AddAzureClients(clientBuilder => { // Register clients for each service - var credential = new DefaultAzureCredential(); - clientBuilder.AddSecretClient(new Uri("")); clientBuilder.AddBlobServiceClient(new Uri("")); clientBuilder.AddServiceBusClient(".servicebus.windows.net"); clientBuilder.UseCredential(new DefaultAzureCredential()); // Register a subclient for each Service Bus Queue - var admin = new ServiceBusAdministrationClient( - ".servicebus.windows.net", credential); - - await foreach (var queue in admin.GetQueuesAsync()) + foreach (var queue in queueNames) { - clientBuilder.AddClient((_, _, provider) => - provider.GetService()! - .CreateSender(queue.Name) - ).WithName(queue.Name); + clientBuilder.AddClient( + (_, _, provider) => provider.GetService()! + .CreateSender(queue)).WithName(queue); } }); WebApplication app = builder.Build(); -#endregion snippet_WebApplicationBuilder + +async Task> GetQueueNames() +{ + // Query the available queues for the Service Bus namespace. + var adminClient = new ServiceBusAdministrationClient + (".servicebus.windows.net", new DefaultAzureCredential()); + var queueNames = new List(); + + // Because the result is async, they need to be captured to a standard list to avoid async + // calls when registering. Failure to do so results in an error with the services collection. + await foreach (var queue in adminClient.GetQueuesAsync()) + { + queueNames.Add(queue.Name); + } + + return queueNames; +} +#endregion if (app.Environment.IsDevelopment()) { From b806cade4767c568acbb33ca6a1faf9fbcaa24b5 Mon Sep 17 00:00:00 2001 From: Alex Wolf Date: Wed, 9 Aug 2023 13:29:30 -0400 Subject: [PATCH 03/24] removed extra file --- .../dependency-injection/Directory.Packages.props | 15 --------------- 1 file changed, 15 deletions(-) delete mode 100644 docs/azure/sdk/snippets/dependency-injection/Directory.Packages.props diff --git a/docs/azure/sdk/snippets/dependency-injection/Directory.Packages.props b/docs/azure/sdk/snippets/dependency-injection/Directory.Packages.props deleted file mode 100644 index 0dc07aa60cabe..0000000000000 --- a/docs/azure/sdk/snippets/dependency-injection/Directory.Packages.props +++ /dev/null @@ -1,15 +0,0 @@ - - - true - - - - - - - - - - - - \ No newline at end of file From a1da61a8b24262f79f2919aee3ce3494d03f4e07 Mon Sep 17 00:00:00 2001 From: Alex Wolf Date: Wed, 9 Aug 2023 13:52:22 -0400 Subject: [PATCH 04/24] fixed conflicts --- docs/azure/sdk/dependency-injection.md | 4 ++-- .../HostApplicationBuilder/Program.cs | 17 -------------- .../HostBuilder/Program.cs | 22 ------------------- .../WebApplicationBuilder/Program.cs | 15 ------------- 4 files changed, 2 insertions(+), 56 deletions(-) diff --git a/docs/azure/sdk/dependency-injection.md b/docs/azure/sdk/dependency-injection.md index ad32557247f29..0f806c8f04c1a 100644 --- a/docs/azure/sdk/dependency-injection.md +++ b/docs/azure/sdk/dependency-injection.md @@ -64,7 +64,7 @@ In the preceding code: ## Use the registered clients -With the clients registered, as described in the [Register clients](#register-clients) section, you can now use them. In the following example, [constructor injection](/dotnet/core/extensions/dependency-injection#constructor-injection-behavior) is used to obtain the Blob Storage client in an ASP.NET Core API controller: +With the clients registered, as described in the [Register clients](#register-clients-and-subclients) section, you can now use them. In the following example, [constructor injection](/dotnet/core/extensions/dependency-injection#constructor-injection-behavior) is used to obtain the Blob Storage client in an ASP.NET Core API controller: ```csharp [ApiController] @@ -97,7 +97,7 @@ public class MyApiController : ControllerBase ## Store configuration separately from code -In the [Register clients](#register-clients) section, you explicitly passed the `Uri`-typed variables to the client constructors. This approach could cause problems when you run code against different environments during development and production. The .NET team suggests [storing such configurations in environment-dependent JSON files](../../core/extensions/configuration-providers.md#json-configuration-provider). For example, you can have an *appsettings.Development.json* file containing development environment settings. Another *appsettings.Production.json* file would contain production environment settings, and so on. The file format is: +In the [Register clients](#register-clients-and-subclients) section, you explicitly passed the `Uri`-typed variables to the client constructors. This approach could cause problems when you run code against different environments during development and production. The .NET team suggests [storing such configurations in environment-dependent JSON files](../../core/extensions/configuration-providers.md#json-configuration-provider). For example, you can have an *appsettings.Development.json* file containing development environment settings. Another *appsettings.Production.json* file would contain production environment settings, and so on. The file format is: ```json { diff --git a/docs/azure/sdk/snippets/dependency-injection/HostApplicationBuilder/Program.cs b/docs/azure/sdk/snippets/dependency-injection/HostApplicationBuilder/Program.cs index 3099a1cb6c3b3..f1968f90795eb 100644 --- a/docs/azure/sdk/snippets/dependency-injection/HostApplicationBuilder/Program.cs +++ b/docs/azure/sdk/snippets/dependency-injection/HostApplicationBuilder/Program.cs @@ -1,5 +1,4 @@ using Azure.Identity; -<<<<<<< HEAD using Azure.Messaging.ServiceBus; using Azure.Messaging.ServiceBus.Administration; using Microsoft.Extensions.Azure; @@ -49,19 +48,3 @@ async Task> GetQueueNames() return queueNames; } -======= -using Microsoft.Extensions.Azure; -using Microsoft.Extensions.Hosting; - -HostApplicationBuilder builder = Host.CreateApplicationBuilder(args); - -builder.Services.AddAzureClients(clientBuilder => -{ - clientBuilder.AddSecretClient(new Uri("")); - clientBuilder.AddBlobServiceClient(new Uri("")); - clientBuilder.UseCredential(new DefaultAzureCredential()); -}); - -using IHost host = builder.Build(); -await host.RunAsync(); ->>>>>>> main diff --git a/docs/azure/sdk/snippets/dependency-injection/HostBuilder/Program.cs b/docs/azure/sdk/snippets/dependency-injection/HostBuilder/Program.cs index 91188360c79d5..3740a80be0379 100644 --- a/docs/azure/sdk/snippets/dependency-injection/HostBuilder/Program.cs +++ b/docs/azure/sdk/snippets/dependency-injection/HostBuilder/Program.cs @@ -1,4 +1,3 @@ -<<<<<<< HEAD #region snippet_HostBuilder using Azure.Identity; using Azure.Messaging.ServiceBus; @@ -46,25 +45,4 @@ async Task> GetQueueNames() return queueNames; } -======= -using HostBuilder; -#region snippet_HostBuilder -using Azure.Identity; -using Microsoft.Extensions.Azure; - -IHost host = Host.CreateDefaultBuilder(args) - .ConfigureServices(services => - { - services.AddHostedService(); - services.AddAzureClients(clientBuilder => - { - clientBuilder.AddSecretClient(new Uri("")); - clientBuilder.AddBlobServiceClient(new Uri("")); - clientBuilder.UseCredential(new DefaultAzureCredential()); - }); - }) - .Build(); - -await host.RunAsync(); ->>>>>>> main #endregion snippet_HostBuilder diff --git a/docs/azure/sdk/snippets/dependency-injection/WebApplicationBuilder/Program.cs b/docs/azure/sdk/snippets/dependency-injection/WebApplicationBuilder/Program.cs index c15aba9d58f10..cb53cc28e1ef1 100644 --- a/docs/azure/sdk/snippets/dependency-injection/WebApplicationBuilder/Program.cs +++ b/docs/azure/sdk/snippets/dependency-injection/WebApplicationBuilder/Program.cs @@ -1,15 +1,11 @@ #region snippet_WebApplicationBuilder using Azure.Identity; -<<<<<<< HEAD using Azure.Messaging.ServiceBus; using Azure.Messaging.ServiceBus.Administration; -======= ->>>>>>> main using Microsoft.Extensions.Azure; WebApplicationBuilder builder = WebApplication.CreateBuilder(args); -<<<<<<< HEAD var queueNames = await GetQueueNames(); builder.Services.AddAzureClients(clientBuilder => @@ -48,17 +44,6 @@ async Task> GetQueueNames() return queueNames; } #endregion -======= -builder.Services.AddAzureClients(clientBuilder => -{ - clientBuilder.AddSecretClient(new Uri("")); - clientBuilder.AddBlobServiceClient(new Uri("")); - clientBuilder.UseCredential(new DefaultAzureCredential()); -}); - -WebApplication app = builder.Build(); -#endregion snippet_WebApplicationBuilder ->>>>>>> main if (app.Environment.IsDevelopment()) { From f51aeda824b376696d59884d44d9b1bc2c659311 Mon Sep 17 00:00:00 2001 From: Alex Wolf Date: Wed, 9 Aug 2023 13:57:37 -0400 Subject: [PATCH 05/24] fixed csproj --- .../HostApplicationBuilder/HostApplicationBuilder.csproj | 3 --- .../dependency-injection/HostBuilder/HostBuilder.csproj | 3 --- .../WebApplicationBuilder/WebApplicationBuilder.csproj | 3 --- 3 files changed, 9 deletions(-) diff --git a/docs/azure/sdk/snippets/dependency-injection/HostApplicationBuilder/HostApplicationBuilder.csproj b/docs/azure/sdk/snippets/dependency-injection/HostApplicationBuilder/HostApplicationBuilder.csproj index f34974b5f1c9e..54b28c586b873 100644 --- a/docs/azure/sdk/snippets/dependency-injection/HostApplicationBuilder/HostApplicationBuilder.csproj +++ b/docs/azure/sdk/snippets/dependency-injection/HostApplicationBuilder/HostApplicationBuilder.csproj @@ -9,10 +9,7 @@ -<<<<<<< HEAD -======= ->>>>>>> main diff --git a/docs/azure/sdk/snippets/dependency-injection/HostBuilder/HostBuilder.csproj b/docs/azure/sdk/snippets/dependency-injection/HostBuilder/HostBuilder.csproj index 4be71bf8e8a5a..393da41132e87 100644 --- a/docs/azure/sdk/snippets/dependency-injection/HostBuilder/HostBuilder.csproj +++ b/docs/azure/sdk/snippets/dependency-injection/HostBuilder/HostBuilder.csproj @@ -9,10 +9,7 @@ -<<<<<<< HEAD -======= ->>>>>>> main diff --git a/docs/azure/sdk/snippets/dependency-injection/WebApplicationBuilder/WebApplicationBuilder.csproj b/docs/azure/sdk/snippets/dependency-injection/WebApplicationBuilder/WebApplicationBuilder.csproj index 408297b06de3f..87ea3e207d5ae 100644 --- a/docs/azure/sdk/snippets/dependency-injection/WebApplicationBuilder/WebApplicationBuilder.csproj +++ b/docs/azure/sdk/snippets/dependency-injection/WebApplicationBuilder/WebApplicationBuilder.csproj @@ -10,10 +10,7 @@ -<<<<<<< HEAD -======= ->>>>>>> main From e819db1d447284326e91582977daac2b83328645 Mon Sep 17 00:00:00 2001 From: Alex Wolf Date: Wed, 9 Aug 2023 13:58:15 -0400 Subject: [PATCH 06/24] Fixed link --- docs/azure/sdk/logging.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/azure/sdk/logging.md b/docs/azure/sdk/logging.md index 839863a5f3e25..6a7b9d8553c99 100644 --- a/docs/azure/sdk/logging.md +++ b/docs/azure/sdk/logging.md @@ -154,7 +154,7 @@ Using the Azure Service Bus library as an example, complete the following steps: ### Logging without client registration -There are scenarios in which [registering an Azure SDK library's client with the DI container](dependency-injection.md#register-clients) is either impossible or unnecessary: +There are scenarios in which [registering an Azure SDK library's client with the DI container](dependency-injection.md#register-clients-and-subclients) is either impossible or unnecessary: - The Azure SDK library doesn't include an `IServiceCollection` extension method to register a client in the DI container. - Your app uses Azure extension libraries that depend on other Azure SDK libraries. Examples of such Azure extension libraries include: From c13afef96a6e5c31aadef0e3b50b4685cc3a7bfb Mon Sep 17 00:00:00 2001 From: Alex Wolf Date: Wed, 9 Aug 2023 14:04:30 -0400 Subject: [PATCH 07/24] fix version --- .../sdk/snippets/dependency-injection/Directory.Packages.props | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/azure/sdk/snippets/dependency-injection/Directory.Packages.props b/docs/azure/sdk/snippets/dependency-injection/Directory.Packages.props index e0495eadc37f5..b60632a2f7ae9 100644 --- a/docs/azure/sdk/snippets/dependency-injection/Directory.Packages.props +++ b/docs/azure/sdk/snippets/dependency-injection/Directory.Packages.props @@ -5,6 +5,7 @@ + From 59a3c08f21e25135a90cc1e20707a9a0cb67b4ab Mon Sep 17 00:00:00 2001 From: Alex Wolf Date: Wed, 9 Aug 2023 14:32:40 -0400 Subject: [PATCH 08/24] updates --- docs/azure/sdk/dependency-injection.md | 24 ++----------------- .../HostApplicationBuilder/Program.cs | 2 +- .../HostBuilder/Program.cs | 2 +- .../WebApplicationBuilder/Program.cs | 2 +- 4 files changed, 5 insertions(+), 25 deletions(-) diff --git a/docs/azure/sdk/dependency-injection.md b/docs/azure/sdk/dependency-injection.md index 0f806c8f04c1a..6a47ee077b4a7 100644 --- a/docs/azure/sdk/dependency-injection.md +++ b/docs/azure/sdk/dependency-injection.md @@ -36,11 +36,9 @@ dotnet add package Azure.Storage.ServiceBus ## Register clients and subclients -A service client is the entry point to the API for an Azure service – from it, library users can invoke all operations the service provides and can easily implement the most common scenarios. In the *Program.cs* file, invoke the extension method to register a client for each service. +A service client is the entry point to the API for an Azure service – from it, library users can invoke all operations the service provides and can easily implement the most common scenarios. Where it will simplify an API's design, groups of service calls can be organized around smaller subclient types. For example, `ServiceBusClient` can register additional `ServiceBusSender` clients to simplify working with queues. -Where it will simplify an API's design, groups of service calls can be organized around smaller subclient types. For example, `ServiceBusClient` can register additional `ServiceBusSender` clients to simplify working with queues. - -The following code samples provide guidance on application builders from the `Microsoft.AspNetCore.Builder` and `Microsoft.Extensions.Hosting` namespaces. +In the *Program.cs* file, invoke the extension method to register a client for each service. The following code samples provide guidance on application builders from the `Microsoft.AspNetCore.Builder` and `Microsoft.Extensions.Hosting` namespaces. ### [WebApplicationBuilder](#tab/web-app-builder) @@ -116,9 +114,6 @@ In the [Register clients](#register-clients-and-subclients) section, you explici }, "Storage": { "ServiceUri": "https://mydemoaccount.storage.windows.net" - }, - "ServiceBus": { - "ServiceUri": "https://mydemoaccount.storage.windows.net" } } ``` @@ -135,12 +130,6 @@ builder.Services.AddAzureClients(clientBuilder => clientBuilder.AddBlobServiceClient( builder.Configuration.GetSection("Storage")); -<<<<<<< HEAD - - clientBuilder.AddServiceBusClient( - builder.Configuration.GetSection("ServiceBus")); -======= ->>>>>>> main clientBuilder.UseCredential(new DefaultAzureCredential()); @@ -161,12 +150,6 @@ builder.Services.AddAzureClients(clientBuilder => clientBuilder.AddBlobServiceClient( builder.Configuration.GetSection("Storage")); -<<<<<<< HEAD - clientBuilder.AddServiceBusClient( - builder.Configuration.GetSection("ServiceBus")); - -======= ->>>>>>> main clientBuilder.UseCredential(new DefaultAzureCredential()); // Set up any default settings @@ -190,9 +173,6 @@ IHost host = Host.CreateDefaultBuilder(args) clientBuilder.AddBlobServiceClient( hostContext.Configuration.GetSection("Storage")); - clientBuilder.AddServiceBusClient( - hostContext.Configuration.GetSection("ServiceBus")); - clientBuilder.UseCredential(new DefaultAzureCredential()); // Set up any default settings diff --git a/docs/azure/sdk/snippets/dependency-injection/HostApplicationBuilder/Program.cs b/docs/azure/sdk/snippets/dependency-injection/HostApplicationBuilder/Program.cs index f1968f90795eb..8daa04be895ac 100644 --- a/docs/azure/sdk/snippets/dependency-injection/HostApplicationBuilder/Program.cs +++ b/docs/azure/sdk/snippets/dependency-injection/HostApplicationBuilder/Program.cs @@ -14,7 +14,7 @@ // Register clients for each service clientBuilder.AddSecretClient(new Uri("")); clientBuilder.AddBlobServiceClient(new Uri("")); - clientBuilder.AddServiceBusClient(".servicebus.windows.net"); + clientBuilder.AddServiceBusClient(""); clientBuilder.UseCredential(new DefaultAzureCredential()); // Register subclients for Service Bus diff --git a/docs/azure/sdk/snippets/dependency-injection/HostBuilder/Program.cs b/docs/azure/sdk/snippets/dependency-injection/HostBuilder/Program.cs index 3740a80be0379..86a410dfc6dda 100644 --- a/docs/azure/sdk/snippets/dependency-injection/HostBuilder/Program.cs +++ b/docs/azure/sdk/snippets/dependency-injection/HostBuilder/Program.cs @@ -14,7 +14,7 @@ // Register clients for each service clientBuilder.AddSecretClient(new Uri("")); clientBuilder.AddBlobServiceClient(new Uri("")); - clientBuilder.AddServiceBusClient(".servicebus.windows.net"); + clientBuilder.AddServiceBusClient(""); clientBuilder.UseCredential(new DefaultAzureCredential()); // Register a subclient for each Service Bus Queue diff --git a/docs/azure/sdk/snippets/dependency-injection/WebApplicationBuilder/Program.cs b/docs/azure/sdk/snippets/dependency-injection/WebApplicationBuilder/Program.cs index cb53cc28e1ef1..4243a423342fd 100644 --- a/docs/azure/sdk/snippets/dependency-injection/WebApplicationBuilder/Program.cs +++ b/docs/azure/sdk/snippets/dependency-injection/WebApplicationBuilder/Program.cs @@ -13,7 +13,7 @@ // Register clients for each service clientBuilder.AddSecretClient(new Uri("")); clientBuilder.AddBlobServiceClient(new Uri("")); - clientBuilder.AddServiceBusClient(".servicebus.windows.net"); + clientBuilder.AddServiceBusClient(""); clientBuilder.UseCredential(new DefaultAzureCredential()); // Register a subclient for each Service Bus Queue From 19966c60308fca8251e271ce821ea074def9f911 Mon Sep 17 00:00:00 2001 From: Alex Wolf Date: Wed, 9 Aug 2023 15:23:34 -0400 Subject: [PATCH 09/24] updates --- docs/azure/sdk/dependency-injection.md | 15 +++++++++++++++ .../HostApplicationBuilder/Program.cs | 4 ++-- .../dependency-injection/HostBuilder/Program.cs | 4 ++-- .../WebApplicationBuilder/Program.cs | 4 ++-- 4 files changed, 21 insertions(+), 6 deletions(-) diff --git a/docs/azure/sdk/dependency-injection.md b/docs/azure/sdk/dependency-injection.md index 6a47ee077b4a7..7aedb1c3817c5 100644 --- a/docs/azure/sdk/dependency-injection.md +++ b/docs/azure/sdk/dependency-injection.md @@ -114,6 +114,9 @@ In the [Register clients](#register-clients-and-subclients) section, you explici }, "Storage": { "ServiceUri": "https://mydemoaccount.storage.windows.net" + }, + "ServiceBus": { + "ServiceUri": "https://.servicebus.windows.net" } } ``` @@ -131,6 +134,9 @@ builder.Services.AddAzureClients(clientBuilder => clientBuilder.AddBlobServiceClient( builder.Configuration.GetSection("Storage")); + clientBuilder.AddServiceBusClientWithNamespace( + builder.Configuration.GetSection("ServiceBus")); + clientBuilder.UseCredential(new DefaultAzureCredential()); // Set up any default settings @@ -150,6 +156,9 @@ builder.Services.AddAzureClients(clientBuilder => clientBuilder.AddBlobServiceClient( builder.Configuration.GetSection("Storage")); + clientBuilder.AddServiceBusClientWithNamespace( + builder.Configuration.GetSection("ServiceBus")); + clientBuilder.UseCredential(new DefaultAzureCredential()); // Set up any default settings @@ -173,6 +182,9 @@ IHost host = Host.CreateDefaultBuilder(args) clientBuilder.AddBlobServiceClient( hostContext.Configuration.GetSection("Storage")); + clientBuilder.AddServiceBusClientWithNamespace( + hostContext.Configuration.GetSection("ServiceBus")); + clientBuilder.UseCredential(new DefaultAzureCredential()); // Set up any default settings @@ -246,6 +258,9 @@ At some point, you may want to change the default settings for a service client. "Storage": { "ServiceUri": "https://store1.storage.windows.net" }, + "ServiceBus": { + "ServiceUri": "https://.servicebus.windows.net" + }, "CustomStorage": { "ServiceUri": "https://store2.storage.windows.net" } diff --git a/docs/azure/sdk/snippets/dependency-injection/HostApplicationBuilder/Program.cs b/docs/azure/sdk/snippets/dependency-injection/HostApplicationBuilder/Program.cs index 8daa04be895ac..48228908fd0f2 100644 --- a/docs/azure/sdk/snippets/dependency-injection/HostApplicationBuilder/Program.cs +++ b/docs/azure/sdk/snippets/dependency-injection/HostApplicationBuilder/Program.cs @@ -14,7 +14,7 @@ // Register clients for each service clientBuilder.AddSecretClient(new Uri("")); clientBuilder.AddBlobServiceClient(new Uri("")); - clientBuilder.AddServiceBusClient(""); + clientBuilder.AddServiceBusClientWithNamespace(".servicebus.windows.net"); clientBuilder.UseCredential(new DefaultAzureCredential()); // Register subclients for Service Bus @@ -36,7 +36,7 @@ async Task> GetQueueNames() { // Query the available queues for the Service Bus namespace. var adminClient = new ServiceBusAdministrationClient - (".servicebus.windows.net", new DefaultAzureCredential()); + (".servicebus.windows.net", new DefaultAzureCredential()); var queueNames = new List(); // Because the result is async, they need to be captured to a standard list to avoid async diff --git a/docs/azure/sdk/snippets/dependency-injection/HostBuilder/Program.cs b/docs/azure/sdk/snippets/dependency-injection/HostBuilder/Program.cs index 86a410dfc6dda..edb6d9f72cb74 100644 --- a/docs/azure/sdk/snippets/dependency-injection/HostBuilder/Program.cs +++ b/docs/azure/sdk/snippets/dependency-injection/HostBuilder/Program.cs @@ -14,7 +14,7 @@ // Register clients for each service clientBuilder.AddSecretClient(new Uri("")); clientBuilder.AddBlobServiceClient(new Uri("")); - clientBuilder.AddServiceBusClient(""); + clientBuilder.AddServiceBusClientWithNamespace(".servicebus.windows.net"); clientBuilder.UseCredential(new DefaultAzureCredential()); // Register a subclient for each Service Bus Queue @@ -33,7 +33,7 @@ async Task> GetQueueNames() { // Query the available queues for the Service Bus namespace. var adminClient = new ServiceBusAdministrationClient - (".servicebus.windows.net", new DefaultAzureCredential()); + (".servicebus.windows.net", new DefaultAzureCredential()); var queueNames = new List(); // Because the result is async, they need to be captured to a standard list to avoid async diff --git a/docs/azure/sdk/snippets/dependency-injection/WebApplicationBuilder/Program.cs b/docs/azure/sdk/snippets/dependency-injection/WebApplicationBuilder/Program.cs index 4243a423342fd..079877c7264bd 100644 --- a/docs/azure/sdk/snippets/dependency-injection/WebApplicationBuilder/Program.cs +++ b/docs/azure/sdk/snippets/dependency-injection/WebApplicationBuilder/Program.cs @@ -13,7 +13,7 @@ // Register clients for each service clientBuilder.AddSecretClient(new Uri("")); clientBuilder.AddBlobServiceClient(new Uri("")); - clientBuilder.AddServiceBusClient(""); + clientBuilder.AddServiceBusClientWithNamespace(".servicebus.windows.net"); clientBuilder.UseCredential(new DefaultAzureCredential()); // Register a subclient for each Service Bus Queue @@ -31,7 +31,7 @@ async Task> GetQueueNames() { // Query the available queues for the Service Bus namespace. var adminClient = new ServiceBusAdministrationClient - (".servicebus.windows.net", new DefaultAzureCredential()); + (".servicebus.windows.net", new DefaultAzureCredential()); var queueNames = new List(); // Because the result is async, they need to be captured to a standard list to avoid async From 7562851c8e844b2c9782e8db7656c65ca9e79709 Mon Sep 17 00:00:00 2001 From: Alex Wolf Date: Wed, 9 Aug 2023 15:24:56 -0400 Subject: [PATCH 10/24] updates --- docs/azure/sdk/dependency-injection.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/azure/sdk/dependency-injection.md b/docs/azure/sdk/dependency-injection.md index 7aedb1c3817c5..d6d356084eac9 100644 --- a/docs/azure/sdk/dependency-injection.md +++ b/docs/azure/sdk/dependency-injection.md @@ -42,7 +42,7 @@ In the *Program.cs* file, invoke the Date: Wed, 9 Aug 2023 15:37:07 -0400 Subject: [PATCH 11/24] fix highlights --- docs/azure/sdk/dependency-injection.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/azure/sdk/dependency-injection.md b/docs/azure/sdk/dependency-injection.md index d6d356084eac9..bd62f72b0baf5 100644 --- a/docs/azure/sdk/dependency-injection.md +++ b/docs/azure/sdk/dependency-injection.md @@ -42,7 +42,7 @@ In the *Program.cs* file, invoke the Date: Wed, 9 Aug 2023 15:56:06 -0400 Subject: [PATCH 12/24] refactor --- docs/azure/sdk/dependency-injection.md | 16 ++++++++++------ .../HostApplicationBuilder/Program.cs | 2 ++ 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/docs/azure/sdk/dependency-injection.md b/docs/azure/sdk/dependency-injection.md index bd62f72b0baf5..ec0040184259d 100644 --- a/docs/azure/sdk/dependency-injection.md +++ b/docs/azure/sdk/dependency-injection.md @@ -56,7 +56,7 @@ In the *Program.cs* file, invoke the and , respectively. The `Uri`-typed arguments are passed. To avoid specifying these URLs explicitly, see the [Store configuration separately from code](#store-configuration-separately-from-code) section. +* Key Vault Secrets, Blob Storage and Service Bus clients are registered using the , and , respectively. The `Uri` and `string`-typed arguments are passed. To avoid specifying these URLs explicitly, see the [Store configuration separately from code](#store-configuration-separately-from-code) section. * is used to satisfy the `TokenCredential` argument requirement for each registered client. When one of the clients is created, `DefaultAzureCredential` is used to authenticate. * Service Bus subclients are registered for each queue on the service using the subclient and corresponding options types. @@ -116,7 +116,7 @@ In the [Register clients](#register-clients-and-subclients) section, you explici "ServiceUri": "https://mydemoaccount.storage.windows.net" }, "ServiceBus": { - "ServiceUri": "https://.servicebus.windows.net" + "NamespaceUri": "https://.servicebus.windows.net" } } ``` @@ -135,7 +135,7 @@ builder.Services.AddAzureClients(clientBuilder => builder.Configuration.GetSection("Storage")); clientBuilder.AddServiceBusClientWithNamespace( - builder.Configuration.GetSection("ServiceBus")); + builder.Configuration["ServiceBus:NamespaceUri"]); clientBuilder.UseCredential(new DefaultAzureCredential()); @@ -157,7 +157,7 @@ builder.Services.AddAzureClients(clientBuilder => builder.Configuration.GetSection("Storage")); clientBuilder.AddServiceBusClientWithNamespace( - builder.Configuration.GetSection("ServiceBus")); + builder.Configuration["ServiceBus:NamespaceUri"]); clientBuilder.UseCredential(new DefaultAzureCredential()); @@ -183,7 +183,7 @@ IHost host = Host.CreateDefaultBuilder(args) hostContext.Configuration.GetSection("Storage")); clientBuilder.AddServiceBusClientWithNamespace( - hostContext.Configuration.GetSection("ServiceBus")); + hostContext.Configuration["ServiceBus:NamespaceUri"]); clientBuilder.UseCredential(new DefaultAzureCredential()); @@ -259,7 +259,7 @@ At some point, you may want to change the default settings for a service client. "ServiceUri": "https://store1.storage.windows.net" }, "ServiceBus": { - "ServiceUri": "https://.servicebus.windows.net" + "NamespaceUri": "https://.servicebus.windows.net" }, "CustomStorage": { "ServiceUri": "https://store2.storage.windows.net" @@ -286,6 +286,10 @@ builder.Services.AddAzureClients(clientBuilder => builder.Configuration.GetSection("Storage")) .ConfigureOptions(options => options.Retry.MaxRetries = 10); + clientBuilder.AddServiceBusClientWithNamespace( + builder.Configuration["ServiceBus:NamespaceUri"]) + .ConfigureOptions(options => options.RetryOptions.MaxRetries = 10); + // A named storage client with a different custom retry policy clientBuilder.AddBlobServiceClient( builder.Configuration.GetSection("CustomStorage")) diff --git a/docs/azure/sdk/snippets/dependency-injection/HostApplicationBuilder/Program.cs b/docs/azure/sdk/snippets/dependency-injection/HostApplicationBuilder/Program.cs index 48228908fd0f2..cd7e530475a14 100644 --- a/docs/azure/sdk/snippets/dependency-injection/HostApplicationBuilder/Program.cs +++ b/docs/azure/sdk/snippets/dependency-injection/HostApplicationBuilder/Program.cs @@ -17,6 +17,8 @@ clientBuilder.AddServiceBusClientWithNamespace(".servicebus.windows.net"); clientBuilder.UseCredential(new DefaultAzureCredential()); + + // Register subclients for Service Bus foreach (var queueName in queueNames) { From 725279406f78d769b91d2494c7d16971ebe971d0 Mon Sep 17 00:00:00 2001 From: Alex Wolf Date: Wed, 9 Aug 2023 16:08:22 -0400 Subject: [PATCH 13/24] fix package --- docs/azure/sdk/dependency-injection.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/azure/sdk/dependency-injection.md b/docs/azure/sdk/dependency-injection.md index ec0040184259d..778c97b25706e 100644 --- a/docs/azure/sdk/dependency-injection.md +++ b/docs/azure/sdk/dependency-injection.md @@ -31,7 +31,7 @@ For demonstration purposes, the sample code in this article uses the Key Vault S ```dotnetcli dotnet add package Azure.Security.KeyVault.Secrets dotnet add package Azure.Storage.Blobs -dotnet add package Azure.Storage.ServiceBus +dotnet add package Azure.Messaging.ServiceBus ``` ## Register clients and subclients From a1512a9e46282c7fa260d5a7923cb1023961dfbc Mon Sep 17 00:00:00 2001 From: Alex Wolf Date: Wed, 9 Aug 2023 16:14:00 -0400 Subject: [PATCH 14/24] fix line numbers --- docs/azure/sdk/dependency-injection.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/azure/sdk/dependency-injection.md b/docs/azure/sdk/dependency-injection.md index 778c97b25706e..cb92dfa7e7c18 100644 --- a/docs/azure/sdk/dependency-injection.md +++ b/docs/azure/sdk/dependency-injection.md @@ -42,7 +42,7 @@ In the *Program.cs* file, invoke the Date: Wed, 9 Aug 2023 16:23:18 -0400 Subject: [PATCH 15/24] fix --- docs/azure/sdk/dependency-injection.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/azure/sdk/dependency-injection.md b/docs/azure/sdk/dependency-injection.md index cb92dfa7e7c18..f95a404e3e933 100644 --- a/docs/azure/sdk/dependency-injection.md +++ b/docs/azure/sdk/dependency-injection.md @@ -203,7 +203,7 @@ In the preceding JSON sample: * The `AzureDefaults.Retry` object literal: * Represents the [retry policy configuration settings](#configure-a-new-retry-policy). * Corresponds to the property. Within that object literal, you find the `MaxRetries` key, which corresponds to the property. -* The `KeyVault:VaultUri` and `Storage:ServiceUri` key values map to the `Uri`-typed arguments of the and constructor overloads, respectively. The `TokenCredential` variants of the constructors are used because a default `TokenCredential` is set via the method call. +* The `KeyVault:VaultUri`, `Storage:ServiceUri` and `ServiceBus:NamespaceUri` key values map to the `Uri` and `string`-typed arguments of the , and constructor overloads, respectively. The `TokenCredential` variants of the constructors are used because a default `TokenCredential` is set via the method call. ## Configure multiple service clients with different names From 51a5d9eb174edf19369a86f5403c560d0821d831 Mon Sep 17 00:00:00 2001 From: Alex Wolf Date: Wed, 9 Aug 2023 16:31:20 -0400 Subject: [PATCH 16/24] fix --- .../dependency-injection/HostApplicationBuilder/Program.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/docs/azure/sdk/snippets/dependency-injection/HostApplicationBuilder/Program.cs b/docs/azure/sdk/snippets/dependency-injection/HostApplicationBuilder/Program.cs index cd7e530475a14..48228908fd0f2 100644 --- a/docs/azure/sdk/snippets/dependency-injection/HostApplicationBuilder/Program.cs +++ b/docs/azure/sdk/snippets/dependency-injection/HostApplicationBuilder/Program.cs @@ -17,8 +17,6 @@ clientBuilder.AddServiceBusClientWithNamespace(".servicebus.windows.net"); clientBuilder.UseCredential(new DefaultAzureCredential()); - - // Register subclients for Service Bus foreach (var queueName in queueNames) { From c2734962ef7e28ca15227512a8098c8e2718796c Mon Sep 17 00:00:00 2001 From: alexwolfmsft <93200798+alexwolfmsft@users.noreply.github.com> Date: Wed, 9 Aug 2023 16:56:55 -0400 Subject: [PATCH 17/24] Apply suggestions from code review Co-authored-by: Scott Addie <10702007+scottaddie@users.noreply.github.com> --- docs/azure/sdk/dependency-injection.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/azure/sdk/dependency-injection.md b/docs/azure/sdk/dependency-injection.md index f95a404e3e933..46d8f7e372578 100644 --- a/docs/azure/sdk/dependency-injection.md +++ b/docs/azure/sdk/dependency-injection.md @@ -62,7 +62,7 @@ In the preceding code: ## Use the registered clients -With the clients registered, as described in the [Register clients](#register-clients-and-subclients) section, you can now use them. In the following example, [constructor injection](/dotnet/core/extensions/dependency-injection#constructor-injection-behavior) is used to obtain the Blob Storage client in an ASP.NET Core API controller: +With the clients registered, as described in the [Register clients and subclients](#register-clients-and-subclients) section, you can now use them. In the following example, [constructor injection](/dotnet/core/extensions/dependency-injection#constructor-injection-behavior) is used to obtain the Blob Storage client in an ASP.NET Core API controller: ```csharp [ApiController] @@ -95,7 +95,7 @@ public class MyApiController : ControllerBase ## Store configuration separately from code -In the [Register clients](#register-clients-and-subclients) section, you explicitly passed the `Uri`-typed variables to the client constructors. This approach could cause problems when you run code against different environments during development and production. The .NET team suggests [storing such configurations in environment-dependent JSON files](../../core/extensions/configuration-providers.md#json-configuration-provider). For example, you can have an *appsettings.Development.json* file containing development environment settings. Another *appsettings.Production.json* file would contain production environment settings, and so on. The file format is: +In the [Register clients and subclients](#register-clients-and-subclients) section, you explicitly passed the `Uri`-typed variables to the client constructors. This approach could cause problems when you run code against different environments during development and production. The .NET team suggests [storing such configurations in environment-dependent JSON files](../../core/extensions/configuration-providers.md#json-configuration-provider). For example, you can have an *appsettings.Development.json* file containing development environment settings. Another *appsettings.Production.json* file would contain production environment settings, and so on. The file format is: ```json { From bf5935c4b7f4467ec832a270258fb56565dfc20e Mon Sep 17 00:00:00 2001 From: Alex Wolf Date: Thu, 10 Aug 2023 09:06:59 -0400 Subject: [PATCH 18/24] tweaks --- docs/azure/sdk/dependency-injection.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/azure/sdk/dependency-injection.md b/docs/azure/sdk/dependency-injection.md index 0c39774ff704b..da3255e1c8df1 100644 --- a/docs/azure/sdk/dependency-injection.md +++ b/docs/azure/sdk/dependency-injection.md @@ -26,7 +26,7 @@ To register and configure service clients from an [`Azure.`-prefixed package](pa dotnet add package Azure.Identity ``` -For demonstration purposes, the sample code in this article uses the Key Vault Secrets and Blob Storage libraries. Install the following packages to follow along: +For demonstration purposes, the sample code in this article uses the Key Vault Secrets, Blob Storage and Service Bus libraries. Install the following packages to follow along: ```dotnetcli dotnet add package Azure.Security.KeyVault.Secrets @@ -58,7 +58,7 @@ In the preceding code: * Key Vault Secrets, Blob Storage and Service Bus clients are registered using the , and , respectively. The `Uri` and `string`-typed arguments are passed. To avoid specifying these URLs explicitly, see the [Store configuration separately from code](#store-configuration-separately-from-code) section. * is used to satisfy the `TokenCredential` argument requirement for each registered client. When one of the clients is created, `DefaultAzureCredential` is used to authenticate. -* Service Bus subclients are registered for each queue on the service using the subclient and corresponding options types. +* Service Bus subclients are registered for each queue on the service using the subclient and corresponding options types. The queue names for the subclients are retrieved using a separate method outside of the service registration because the `GetQueuesAsync` method must be run asynchronously. ## Use the registered clients @@ -199,7 +199,7 @@ IHost host = Host.CreateDefaultBuilder(args) In the preceding JSON sample: -* The top-level key names, `AzureDefaults`, `KeyVault`, and `Storage`, are arbitrary. All other key names hold significance, and JSON serialization is performed in a case-insensitive manner. +* The top-level key names, `AzureDefaults`, `KeyVault`, `Storage` and `ServiceBus`, are arbitrary. All other key names hold significance, and JSON serialization is performed in a case-insensitive manner. * The `AzureDefaults.Retry` object literal: * Represents the [retry policy configuration settings](#configure-a-new-retry-policy). * Corresponds to the property. Within that object literal, you find the `MaxRetries` key, which corresponds to the property. From 50d2905e3513e2fa3719a47b8970e13171e743c8 Mon Sep 17 00:00:00 2001 From: alexwolfmsft <93200798+alexwolfmsft@users.noreply.github.com> Date: Thu, 10 Aug 2023 10:22:49 -0400 Subject: [PATCH 19/24] Apply suggestions from code review Co-authored-by: Scott Addie <10702007+scottaddie@users.noreply.github.com> --- docs/azure/sdk/dependency-injection.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/azure/sdk/dependency-injection.md b/docs/azure/sdk/dependency-injection.md index da3255e1c8df1..c6999aee205fd 100644 --- a/docs/azure/sdk/dependency-injection.md +++ b/docs/azure/sdk/dependency-injection.md @@ -26,7 +26,7 @@ To register and configure service clients from an [`Azure.`-prefixed package](pa dotnet add package Azure.Identity ``` -For demonstration purposes, the sample code in this article uses the Key Vault Secrets, Blob Storage and Service Bus libraries. Install the following packages to follow along: +For demonstration purposes, the sample code in this article uses the Key Vault Secrets, Blob Storage, and Service Bus libraries. Install the following packages to follow along: ```dotnetcli dotnet add package Azure.Security.KeyVault.Secrets @@ -36,7 +36,7 @@ dotnet add package Azure.Messaging.ServiceBus ## Register clients and subclients -A service client is the entry point to the API for an Azure service – from it, library users can invoke all operations the service provides and can easily implement the most common scenarios. Where it will simplify an API's design, groups of service calls can be organized around smaller subclient types. For example, `ServiceBusClient` can register additional `ServiceBusSender` clients to simplify working with queues. +A service client is the entry point to the API for an Azure service – from it, library users can invoke all operations the service provides and can easily implement the most common scenarios. Where it will simplify an API's design, groups of service calls can be organized around smaller subclient types. For example, `ServiceBusClient` can register additional `ServiceBusSender` subclients to simplify working with queues. In the *Program.cs* file, invoke the extension method to register a client for each service. The following code samples provide guidance on application builders from the `Microsoft.AspNetCore.Builder` and `Microsoft.Extensions.Hosting` namespaces. @@ -56,7 +56,7 @@ In the *Program.cs* file, invoke the , and , respectively. The `Uri` and `string`-typed arguments are passed. To avoid specifying these URLs explicitly, see the [Store configuration separately from code](#store-configuration-separately-from-code) section. +* Key Vault Secrets, Blob Storage, and Service Bus clients are registered using the , and , respectively. The `Uri`- and `string`-typed arguments are passed. To avoid specifying these URLs explicitly, see the [Store configuration separately from code](#store-configuration-separately-from-code) section. * is used to satisfy the `TokenCredential` argument requirement for each registered client. When one of the clients is created, `DefaultAzureCredential` is used to authenticate. * Service Bus subclients are registered for each queue on the service using the subclient and corresponding options types. The queue names for the subclients are retrieved using a separate method outside of the service registration because the `GetQueuesAsync` method must be run asynchronously. @@ -199,11 +199,11 @@ IHost host = Host.CreateDefaultBuilder(args) In the preceding JSON sample: -* The top-level key names, `AzureDefaults`, `KeyVault`, `Storage` and `ServiceBus`, are arbitrary. All other key names hold significance, and JSON serialization is performed in a case-insensitive manner. +* The top-level key names, `AzureDefaults`, `KeyVault`, `ServiceBus`, and `Storage`, are arbitrary. All other key names hold significance, and JSON serialization is performed in a case-insensitive manner. * The `AzureDefaults.Retry` object literal: * Represents the [retry policy configuration settings](#configure-a-new-retry-policy). * Corresponds to the property. Within that object literal, you find the `MaxRetries` key, which corresponds to the property. -* The `KeyVault:VaultUri`, `Storage:ServiceUri` and `ServiceBus:NamespaceUri` key values map to the `Uri` and `string`-typed arguments of the , and constructor overloads, respectively. The `TokenCredential` variants of the constructors are used because a default `TokenCredential` is set via the method call. +* The `KeyVault:VaultUri`, `ServiceBus:NamespaceUri`, and `Storage:ServiceUri` key values map to the `Uri`- and `string`-typed arguments of the , , and constructor overloads, respectively. The `TokenCredential` variants of the constructors are used because a default `TokenCredential` is set via the method call. ## Configure multiple service clients with different names From d2288903235f3652889586b3633758f5a5029f29 Mon Sep 17 00:00:00 2001 From: Alex Wolf Date: Thu, 10 Aug 2023 10:36:09 -0400 Subject: [PATCH 20/24] pr feedback --- docs/azure/sdk/dependency-injection.md | 12 ++++++------ .../HostApplicationBuilder/Program.cs | 12 ++++++------ .../dependency-injection/HostBuilder/Program.cs | 12 ++++++------ .../WebApplicationBuilder/Program.cs | 12 ++++++------ 4 files changed, 24 insertions(+), 24 deletions(-) diff --git a/docs/azure/sdk/dependency-injection.md b/docs/azure/sdk/dependency-injection.md index da3255e1c8df1..61c403df2cd10 100644 --- a/docs/azure/sdk/dependency-injection.md +++ b/docs/azure/sdk/dependency-injection.md @@ -112,11 +112,11 @@ In the [Register clients and subclients](#register-clients-and-subclients) secti "KeyVault": { "VaultUri": "https://mykeyvault.vault.azure.net" }, - "Storage": { - "ServiceUri": "https://mydemoaccount.storage.windows.net" - }, "ServiceBus": { "NamespaceUri": "https://.servicebus.windows.net" + }, + "Storage": { + "ServiceUri": "https://mydemoaccount.storage.windows.net" } } ``` @@ -255,12 +255,12 @@ At some point, you may want to change the default settings for a service client. "KeyVault": { "VaultUri": "https://mykeyvault.vault.azure.net" }, - "Storage": { - "ServiceUri": "https://store1.storage.windows.net" - }, "ServiceBus": { "NamespaceUri": "https://.servicebus.windows.net" }, + "Storage": { + "ServiceUri": "https://store1.storage.windows.net" + }, "CustomStorage": { "ServiceUri": "https://store2.storage.windows.net" } diff --git a/docs/azure/sdk/snippets/dependency-injection/HostApplicationBuilder/Program.cs b/docs/azure/sdk/snippets/dependency-injection/HostApplicationBuilder/Program.cs index 48228908fd0f2..dd1dc53f90047 100644 --- a/docs/azure/sdk/snippets/dependency-injection/HostApplicationBuilder/Program.cs +++ b/docs/azure/sdk/snippets/dependency-injection/HostApplicationBuilder/Program.cs @@ -4,7 +4,7 @@ using Microsoft.Extensions.Azure; using Microsoft.Extensions.Hosting; -var queueNames = await GetQueueNames(); +List queueNames = await GetQueueNames(); IHost host = Host.CreateDefaultBuilder(args) .ConfigureServices(services => @@ -14,11 +14,11 @@ // Register clients for each service clientBuilder.AddSecretClient(new Uri("")); clientBuilder.AddBlobServiceClient(new Uri("")); - clientBuilder.AddServiceBusClientWithNamespace(".servicebus.windows.net"); + clientBuilder.AddServiceBusClientWithNamespace(".servicebus.windows.net"); clientBuilder.UseCredential(new DefaultAzureCredential()); // Register subclients for Service Bus - foreach (var queueName in queueNames) + foreach (string queueName in queueNames) { clientBuilder.AddClient((_, _, provider) => provider.GetService(typeof(ServiceBusClient)) switch @@ -36,12 +36,12 @@ async Task> GetQueueNames() { // Query the available queues for the Service Bus namespace. var adminClient = new ServiceBusAdministrationClient - (".servicebus.windows.net", new DefaultAzureCredential()); + (".servicebus.windows.net", new DefaultAzureCredential()); var queueNames = new List(); - // Because the result is async, they need to be captured to a standard list to avoid async + // Because the result is async, the queue names need to be captured to a standard list to avoid async // calls when registering. Failure to do so results in an error with the services collection. - await foreach (var queue in adminClient.GetQueuesAsync()) + await foreach (QueueProperties queue in adminClient.GetQueuesAsync()) { queueNames.Add(queue.Name); } diff --git a/docs/azure/sdk/snippets/dependency-injection/HostBuilder/Program.cs b/docs/azure/sdk/snippets/dependency-injection/HostBuilder/Program.cs index edb6d9f72cb74..4d3717fe9510d 100644 --- a/docs/azure/sdk/snippets/dependency-injection/HostBuilder/Program.cs +++ b/docs/azure/sdk/snippets/dependency-injection/HostBuilder/Program.cs @@ -4,7 +4,7 @@ using Azure.Messaging.ServiceBus.Administration; using Microsoft.Extensions.Azure; -var queueNames = await GetQueueNames(); +List queueNames = await GetQueueNames(); IHost host = Host.CreateDefaultBuilder(args) .ConfigureServices(services => @@ -14,11 +14,11 @@ // Register clients for each service clientBuilder.AddSecretClient(new Uri("")); clientBuilder.AddBlobServiceClient(new Uri("")); - clientBuilder.AddServiceBusClientWithNamespace(".servicebus.windows.net"); + clientBuilder.AddServiceBusClientWithNamespace(".servicebus.windows.net"); clientBuilder.UseCredential(new DefaultAzureCredential()); // Register a subclient for each Service Bus Queue - foreach (var queue in queueNames) + foreach (string queue in queueNames) { clientBuilder.AddClient((_, _, provider) => provider.GetService()!.CreateSender(queue) @@ -33,12 +33,12 @@ async Task> GetQueueNames() { // Query the available queues for the Service Bus namespace. var adminClient = new ServiceBusAdministrationClient - (".servicebus.windows.net", new DefaultAzureCredential()); + (".servicebus.windows.net", new DefaultAzureCredential()); var queueNames = new List(); - // Because the result is async, they need to be captured to a standard list to avoid async + // Because the result is async, the queue names need to be captured to a standard list to avoid async // calls when registering. Failure to do so results in an error with the services collection. - await foreach (var queue in adminClient.GetQueuesAsync()) + await foreach (QueueProperties queue in adminClient.GetQueuesAsync()) { queueNames.Add(queue.Name); } diff --git a/docs/azure/sdk/snippets/dependency-injection/WebApplicationBuilder/Program.cs b/docs/azure/sdk/snippets/dependency-injection/WebApplicationBuilder/Program.cs index 079877c7264bd..fcc7c6a6d87d8 100644 --- a/docs/azure/sdk/snippets/dependency-injection/WebApplicationBuilder/Program.cs +++ b/docs/azure/sdk/snippets/dependency-injection/WebApplicationBuilder/Program.cs @@ -6,18 +6,18 @@ WebApplicationBuilder builder = WebApplication.CreateBuilder(args); -var queueNames = await GetQueueNames(); +List queueNames = await GetQueueNames(); builder.Services.AddAzureClients(clientBuilder => { // Register clients for each service clientBuilder.AddSecretClient(new Uri("")); clientBuilder.AddBlobServiceClient(new Uri("")); - clientBuilder.AddServiceBusClientWithNamespace(".servicebus.windows.net"); + clientBuilder.AddServiceBusClientWithNamespace(".servicebus.windows.net"); clientBuilder.UseCredential(new DefaultAzureCredential()); // Register a subclient for each Service Bus Queue - foreach (var queue in queueNames) + foreach (string queue in queueNames) { clientBuilder.AddClient( (_, _, provider) => provider.GetService()! @@ -31,12 +31,12 @@ async Task> GetQueueNames() { // Query the available queues for the Service Bus namespace. var adminClient = new ServiceBusAdministrationClient - (".servicebus.windows.net", new DefaultAzureCredential()); + (".servicebus.windows.net", new DefaultAzureCredential()); var queueNames = new List(); - // Because the result is async, they need to be captured to a standard list to avoid async + // Because the result is async, the queue names need to be captured to a standard list to avoid async // calls when registering. Failure to do so results in an error with the services collection. - await foreach (var queue in adminClient.GetQueuesAsync()) + await foreach (QueueProperties queue in adminClient.GetQueuesAsync()) { queueNames.Add(queue.Name); } From 95a396fff929bbaa3b10723c7dfed07f76a3be74 Mon Sep 17 00:00:00 2001 From: alexwolfmsft <93200798+alexwolfmsft@users.noreply.github.com> Date: Thu, 10 Aug 2023 10:54:39 -0400 Subject: [PATCH 21/24] Apply suggestions from code review Co-authored-by: Jesse Squire --- docs/azure/sdk/dependency-injection.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/azure/sdk/dependency-injection.md b/docs/azure/sdk/dependency-injection.md index 2bfa7a752a5bc..a967734ec1a25 100644 --- a/docs/azure/sdk/dependency-injection.md +++ b/docs/azure/sdk/dependency-injection.md @@ -113,7 +113,7 @@ In the [Register clients and subclients](#register-clients-and-subclients) secti "VaultUri": "https://mykeyvault.vault.azure.net" }, "ServiceBus": { - "NamespaceUri": "https://.servicebus.windows.net" + "Namespace": ".servicebus.windows.net" }, "Storage": { "ServiceUri": "https://mydemoaccount.storage.windows.net" From 9e2f93bf4ad34852342131457be0048f60307ba9 Mon Sep 17 00:00:00 2001 From: Alex Wolf Date: Thu, 10 Aug 2023 10:55:58 -0400 Subject: [PATCH 22/24] removed namespaceuri --- docs/azure/sdk/dependency-injection.md | 12 ++++++------ .../dependency-injection/HostBuilder/Program.cs | 2 +- .../WebApplicationBuilder/Program.cs | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/azure/sdk/dependency-injection.md b/docs/azure/sdk/dependency-injection.md index a967734ec1a25..83bc8de738859 100644 --- a/docs/azure/sdk/dependency-injection.md +++ b/docs/azure/sdk/dependency-injection.md @@ -135,7 +135,7 @@ builder.Services.AddAzureClients(clientBuilder => builder.Configuration.GetSection("Storage")); clientBuilder.AddServiceBusClientWithNamespace( - builder.Configuration["ServiceBus:NamespaceUri"]); + builder.Configuration["ServiceBus:Namespace"]); clientBuilder.UseCredential(new DefaultAzureCredential()); @@ -157,7 +157,7 @@ builder.Services.AddAzureClients(clientBuilder => builder.Configuration.GetSection("Storage")); clientBuilder.AddServiceBusClientWithNamespace( - builder.Configuration["ServiceBus:NamespaceUri"]); + builder.Configuration["ServiceBus:Namespace"]); clientBuilder.UseCredential(new DefaultAzureCredential()); @@ -183,7 +183,7 @@ IHost host = Host.CreateDefaultBuilder(args) hostContext.Configuration.GetSection("Storage")); clientBuilder.AddServiceBusClientWithNamespace( - hostContext.Configuration["ServiceBus:NamespaceUri"]); + hostContext.Configuration["ServiceBus:Namespace"]); clientBuilder.UseCredential(new DefaultAzureCredential()); @@ -203,7 +203,7 @@ In the preceding JSON sample: * The `AzureDefaults.Retry` object literal: * Represents the [retry policy configuration settings](#configure-a-new-retry-policy). * Corresponds to the property. Within that object literal, you find the `MaxRetries` key, which corresponds to the property. -* The `KeyVault:VaultUri`, `ServiceBus:NamespaceUri`, and `Storage:ServiceUri` key values map to the `Uri`- and `string`-typed arguments of the , , and constructor overloads, respectively. The `TokenCredential` variants of the constructors are used because a default `TokenCredential` is set via the method call. +* The `KeyVault:VaultUri`, `ServiceBus:Namespace`, and `Storage:ServiceUri` key values map to the `Uri`- and `string`-typed arguments of the , , and constructor overloads, respectively. The `TokenCredential` variants of the constructors are used because a default `TokenCredential` is set via the method call. ## Configure multiple service clients with different names @@ -256,7 +256,7 @@ At some point, you may want to change the default settings for a service client. "VaultUri": "https://mykeyvault.vault.azure.net" }, "ServiceBus": { - "NamespaceUri": "https://.servicebus.windows.net" + "Namespace": ".servicebus.windows.net" }, "Storage": { "ServiceUri": "https://store1.storage.windows.net" @@ -287,7 +287,7 @@ builder.Services.AddAzureClients(clientBuilder => .ConfigureOptions(options => options.Retry.MaxRetries = 10); clientBuilder.AddServiceBusClientWithNamespace( - builder.Configuration["ServiceBus:NamespaceUri"]) + builder.Configuration["ServiceBus:Namespace"]) .ConfigureOptions(options => options.RetryOptions.MaxRetries = 10); // A named storage client with a different custom retry policy diff --git a/docs/azure/sdk/snippets/dependency-injection/HostBuilder/Program.cs b/docs/azure/sdk/snippets/dependency-injection/HostBuilder/Program.cs index 4d3717fe9510d..79bd9047138ca 100644 --- a/docs/azure/sdk/snippets/dependency-injection/HostBuilder/Program.cs +++ b/docs/azure/sdk/snippets/dependency-injection/HostBuilder/Program.cs @@ -21,7 +21,7 @@ foreach (string queue in queueNames) { clientBuilder.AddClient((_, _, provider) => - provider.GetService()!.CreateSender(queue) + provider.GetService().CreateSender(queue) ).WithName(queue); } }); diff --git a/docs/azure/sdk/snippets/dependency-injection/WebApplicationBuilder/Program.cs b/docs/azure/sdk/snippets/dependency-injection/WebApplicationBuilder/Program.cs index fcc7c6a6d87d8..072e3245cdf0e 100644 --- a/docs/azure/sdk/snippets/dependency-injection/WebApplicationBuilder/Program.cs +++ b/docs/azure/sdk/snippets/dependency-injection/WebApplicationBuilder/Program.cs @@ -20,7 +20,7 @@ foreach (string queue in queueNames) { clientBuilder.AddClient( - (_, _, provider) => provider.GetService()! + (_, _, provider) => provider.GetService() .CreateSender(queue)).WithName(queue); } }); From 11c330c2c5ae5ad01fd5e4d0d7dd1083913c1b12 Mon Sep 17 00:00:00 2001 From: alexwolfmsft <93200798+alexwolfmsft@users.noreply.github.com> Date: Thu, 10 Aug 2023 11:20:15 -0400 Subject: [PATCH 23/24] Apply suggestions from code review Co-authored-by: Jesse Squire --- docs/azure/sdk/dependency-injection.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/azure/sdk/dependency-injection.md b/docs/azure/sdk/dependency-injection.md index 83bc8de738859..95cb764ca27e2 100644 --- a/docs/azure/sdk/dependency-injection.md +++ b/docs/azure/sdk/dependency-injection.md @@ -36,7 +36,7 @@ dotnet add package Azure.Messaging.ServiceBus ## Register clients and subclients -A service client is the entry point to the API for an Azure service – from it, library users can invoke all operations the service provides and can easily implement the most common scenarios. Where it will simplify an API's design, groups of service calls can be organized around smaller subclient types. For example, `ServiceBusClient` can register additional `ServiceBusSender` subclients to simplify working with queues. +A service client is the entry point to the API for an Azure service – from it, library users can invoke all operations the service provides and can easily implement the most common scenarios. Where it will simplify an API's design, groups of service calls can be organized around smaller subclient types. For example, `ServiceBusClient` can register additional `ServiceBusSender` subclients for publishing messages or `ServiceBusReceiver` subclients for consuming messages. In the *Program.cs* file, invoke the extension method to register a client for each service. The following code samples provide guidance on application builders from the `Microsoft.AspNetCore.Builder` and `Microsoft.Extensions.Hosting` namespaces. From 8e9b8a6c06f0e23377e3452f9d0038fcb3338017 Mon Sep 17 00:00:00 2001 From: alexwolfmsft <93200798+alexwolfmsft@users.noreply.github.com> Date: Thu, 10 Aug 2023 20:57:14 -0400 Subject: [PATCH 24/24] Apply suggestions from code review Co-authored-by: Scott Addie <10702007+scottaddie@users.noreply.github.com> --- docs/azure/sdk/dependency-injection.md | 4 ++-- .../HostApplicationBuilder/Program.cs | 5 +++-- .../snippets/dependency-injection/HostBuilder/Program.cs | 5 +++-- .../dependency-injection/WebApplicationBuilder/Program.cs | 8 +++++--- 4 files changed, 13 insertions(+), 9 deletions(-) diff --git a/docs/azure/sdk/dependency-injection.md b/docs/azure/sdk/dependency-injection.md index 95cb764ca27e2..344728d6b5bbd 100644 --- a/docs/azure/sdk/dependency-injection.md +++ b/docs/azure/sdk/dependency-injection.md @@ -113,7 +113,7 @@ In the [Register clients and subclients](#register-clients-and-subclients) secti "VaultUri": "https://mykeyvault.vault.azure.net" }, "ServiceBus": { - "Namespace": ".servicebus.windows.net" + "Namespace": ".servicebus.windows.net" }, "Storage": { "ServiceUri": "https://mydemoaccount.storage.windows.net" @@ -256,7 +256,7 @@ At some point, you may want to change the default settings for a service client. "VaultUri": "https://mykeyvault.vault.azure.net" }, "ServiceBus": { - "Namespace": ".servicebus.windows.net" + "Namespace": ".servicebus.windows.net" }, "Storage": { "ServiceUri": "https://store1.storage.windows.net" diff --git a/docs/azure/sdk/snippets/dependency-injection/HostApplicationBuilder/Program.cs b/docs/azure/sdk/snippets/dependency-injection/HostApplicationBuilder/Program.cs index dd1dc53f90047..c4a061428e197 100644 --- a/docs/azure/sdk/snippets/dependency-injection/HostApplicationBuilder/Program.cs +++ b/docs/azure/sdk/snippets/dependency-injection/HostApplicationBuilder/Program.cs @@ -39,8 +39,9 @@ async Task> GetQueueNames() (".servicebus.windows.net", new DefaultAzureCredential()); var queueNames = new List(); - // Because the result is async, the queue names need to be captured to a standard list to avoid async - // calls when registering. Failure to do so results in an error with the services collection. + // Because the result is async, the queue names need to be captured + // to a standard list to avoid async calls when registering. Failure to + // do so results in an error with the services collection. await foreach (QueueProperties queue in adminClient.GetQueuesAsync()) { queueNames.Add(queue.Name); diff --git a/docs/azure/sdk/snippets/dependency-injection/HostBuilder/Program.cs b/docs/azure/sdk/snippets/dependency-injection/HostBuilder/Program.cs index 79bd9047138ca..6fa1e415cce9f 100644 --- a/docs/azure/sdk/snippets/dependency-injection/HostBuilder/Program.cs +++ b/docs/azure/sdk/snippets/dependency-injection/HostBuilder/Program.cs @@ -36,8 +36,9 @@ async Task> GetQueueNames() (".servicebus.windows.net", new DefaultAzureCredential()); var queueNames = new List(); - // Because the result is async, the queue names need to be captured to a standard list to avoid async - // calls when registering. Failure to do so results in an error with the services collection. + // Because the result is async, the queue names need to be captured + // to a standard list to avoid async calls when registering. Failure to + // do so results in an error with the services collection. await foreach (QueueProperties queue in adminClient.GetQueuesAsync()) { queueNames.Add(queue.Name); diff --git a/docs/azure/sdk/snippets/dependency-injection/WebApplicationBuilder/Program.cs b/docs/azure/sdk/snippets/dependency-injection/WebApplicationBuilder/Program.cs index 072e3245cdf0e..3dd7f253c4ba2 100644 --- a/docs/azure/sdk/snippets/dependency-injection/WebApplicationBuilder/Program.cs +++ b/docs/azure/sdk/snippets/dependency-injection/WebApplicationBuilder/Program.cs @@ -13,7 +13,8 @@ // Register clients for each service clientBuilder.AddSecretClient(new Uri("")); clientBuilder.AddBlobServiceClient(new Uri("")); - clientBuilder.AddServiceBusClientWithNamespace(".servicebus.windows.net"); + clientBuilder.AddServiceBusClientWithNamespace( + ".servicebus.windows.net"); clientBuilder.UseCredential(new DefaultAzureCredential()); // Register a subclient for each Service Bus Queue @@ -34,8 +35,9 @@ async Task> GetQueueNames() (".servicebus.windows.net", new DefaultAzureCredential()); var queueNames = new List(); - // Because the result is async, the queue names need to be captured to a standard list to avoid async - // calls when registering. Failure to do so results in an error with the services collection. + // Because the result is async, the queue names need to be captured + // to a standard list to avoid async calls when registering. Failure to + // do so results in an error with the services collection. await foreach (QueueProperties queue in adminClient.GetQueuesAsync()) { queueNames.Add(queue.Name);