Skip to content

Commit 6f7409d

Browse files
Improve client registration guidance (#49938)
* Improve client registration guidance * edits * edits * fixes * fix * fixes * edits * Fix reuse * Fix * fix * Fix highlight * Apply suggestions from code review Co-authored-by: Scott Addie <[email protected]> * Apply suggestions from code review Co-authored-by: Scott Addie <[email protected]> --------- Co-authored-by: Scott Addie <[email protected]>
1 parent c1b3ff6 commit 6f7409d

File tree

12 files changed

+50
-58
lines changed

12 files changed

+50
-58
lines changed

docs/azure/sdk/aspnetcore-guidance.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ Complete the following steps to register the services you need:
5454
<!-- markdownlint-disable MD023 -->
5555
## [Minimal API](#tab/api)
5656
57-
:::code language="csharp" source="snippets/aspnetcore-guidance/MinApiSample/Program.cs" range="52-73" highlight="1-3,6,8,11-12":::
57+
:::code language="csharp" source="snippets/aspnetcore-guidance/MinApiSample/Program.cs" range="50-71" highlight="1-3,6,8,11-12":::
5858
5959
<!-- markdownlint-disable MD023 -->
6060
## [Blazor](#tab/blazor)
@@ -80,9 +80,9 @@ Use the [Azure Identity](/dotnet/api/overview/azure/identity-readme) library for
8080
dotnet add package Azure.Identity
8181
```
8282
83-
1. In the `Program.cs` file of your app, invoke the <xref:Microsoft.Extensions.Azure.AzureClientFactoryBuilder.UseCredential%2A> extension method from the `Microsoft.Extensions.Azure` library to set a shared `DefaultAzureCredential` instance for all registered Azure service clients:
83+
1. In the `Program.cs` file of your app, invoke the <xref:Microsoft.Extensions.Azure.AzureClientServiceCollectionExtensions.AddAzureClients%2A> extension method from the `Microsoft.Extensions.Azure` library to set a shared `DefaultAzureCredential` instance for all registered Azure service clients:
8484
85-
:::code language="csharp" source="snippets/aspnetcore-guidance/BlazorSample/Program.cs" range="11-30" highlight="19":::
85+
:::code language="csharp" source="snippets/aspnetcore-guidance/BlazorSample/Program.cs" range="11-30" :::
8686
8787
`DefaultAzureCredential` discovers available credentials in the current environment and uses them to authenticate to Azure services. For the order and locations in which `DefaultAzureCredential` scans for credentials, see [DefaultAzureCredential overview](/dotnet/azure/sdk/authentication/credential-chains?tabs=dac#defaultazurecredential-overview). Using a shared `DefaultAzureCredential` instance ensures the underlying token cache is used, which improves application resilience and performance due to fewer requests for a new token.
8888
@@ -106,7 +106,7 @@ Complete the steps in the following sections to update your app to use JSON file
106106
In the preceding JSON sample:
107107
108108
- The top-level key names, `KeyVault`, `ServiceBus`, and `Storage`, are arbitrary names used to reference the config sections from your code. You will pass these names to `AddClient` extension methods to configure a given client. All other key names map to specific client options, and JSON serialization is performed in a case-insensitive manner.
109-
- The `KeyVault:VaultUri`, `ServiceBus:Namespace`, and `Storage:ServiceUri` key values map to the arguments of the <xref:Azure.Security.KeyVault.Secrets.SecretClient.%23ctor(System.Uri,Azure.Core.TokenCredential,Azure.Security.KeyVault.Secrets.SecretClientOptions)?displayProperty=name>, <xref:Azure.Messaging.ServiceBus.ServiceBusClient.%23ctor(System.String)?displayProperty=name>, and <xref:Azure.Storage.Blobs.BlobServiceClient.%23ctor(System.Uri,Azure.Core.TokenCredential,Azure.Storage.Blobs.BlobClientOptions)?displayProperty=name> constructor overloads, respectively. The `TokenCredential` variants of the constructors are used because a default `TokenCredential` is set via the <xref:Microsoft.Extensions.Azure.AzureClientFactoryBuilder.UseCredential(Azure.Core.TokenCredential)?displayProperty=name> method call.
109+
- The `KeyVault:VaultUri`, `ServiceBus:Namespace`, and `Storage:ServiceUri` key values map to the arguments of the <xref:Azure.Security.KeyVault.Secrets.SecretClient.%23ctor(System.Uri,Azure.Core.TokenCredential,Azure.Security.KeyVault.Secrets.SecretClientOptions)?displayProperty=name>, <xref:Azure.Messaging.ServiceBus.ServiceBusClient.%23ctor(System.String)?displayProperty=name>, and <xref:Azure.Storage.Blobs.BlobServiceClient.%23ctor(System.Uri,Azure.Core.TokenCredential,Azure.Storage.Blobs.BlobClientOptions)?displayProperty=name> constructor overloads, respectively.
110110
111111
1. Update the the `Program.cs` file to retrieve the JSON file configurations using `IConfiguration` and pass them into your service registrations:
112112
@@ -122,7 +122,7 @@ You may want to change default Azure client configurations globally or for a spe
122122
123123
2. In the `Program.cs` file, call the `ConfigureDefaults` extension method to retrieve the default settings and apply them to your service clients:
124124
125-
:::code language="csharp" source="snippets/aspnetcore-guidance/MinApiSample/Program.cs" range="14-41" highlight="26-27":::
125+
:::code language="csharp" source="snippets/aspnetcore-guidance/MinApiSample/Program.cs" range="14-41" highlight="24-25":::
126126
127127
## Configure logging
128128

docs/azure/sdk/authentication/best-practices.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,9 @@ For example, consider the following hypothetical sequence of events:
2424

2525
To prevent these types of subtle issues or silent failures in production apps, replace `DefaultAzureCredential` with a specific `TokenCredential` implementation, such as `ManagedIdentityCredential`. See the [**Derived** list](/dotnet/api/azure.core.tokencredential?view=azure-dotnet&preserve-view=true#definition) for options.
2626

27-
For example, consider the following `DefaultAzureCredential` configuration in an ASP.NET Core project:
27+
For example, consider the following configuration in an ASP.NET Core project. An instance of `DefaultAzureCredential` is implicitly created and used for all registered service clients:
2828

29-
:::code language="csharp" source="../snippets/authentication/credential-chains/Program.cs" id="snippet_Dac" highlight="8-9":::
29+
:::code language="csharp" source="../snippets/authentication/credential-chains/Program.cs" id="snippet_Dac" :::
3030

3131
Modify the preceding code to select a credential based on the environment in which the app is running:
3232

docs/azure/sdk/dependency-injection.md

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -43,22 +43,22 @@ In the *Program.cs* file, invoke the <xref:Microsoft.Extensions.Azure.AzureClien
4343

4444
### [WebApplicationBuilder](#tab/web-app-builder)
4545

46-
:::code language="csharp" source="snippets/dependency-injection/WebApplicationBuilder/Program.cs" id="snippet_WebApplicationBuilder" highlight="9-34":::
46+
:::code language="csharp" source="snippets/dependency-injection/WebApplicationBuilder/Program.cs" id="snippet_WebApplicationBuilder" highlight="9-39":::
4747

4848
### [HostApplicationBuilder](#tab/host-app-builder)
4949

50-
:::code language="csharp" source="snippets/dependency-injection/HostApplicationBuilder/Program.cs" highlight="12-39":::
50+
:::code language="csharp" source="snippets/dependency-injection/HostApplicationBuilder/Program.cs" highlight="11-40":::
5151

5252
### [HostBuilder](#tab/host-builder)
5353

54-
:::code language="csharp" source="snippets/dependency-injection/HostBuilder/Program.cs" id="snippet_HostBuilder" highlight="10-34":::
54+
:::code language="csharp" source="snippets/dependency-injection/HostBuilder/Program.cs" id="snippet_HostBuilder" highlight="10-39":::
5555

5656
---
5757

5858
In the preceding code:
5959

6060
* Key Vault Secrets, Blob Storage, and Service Bus clients are registered using the <xref:Microsoft.Extensions.Azure.SecretClientBuilderExtensions.AddSecretClient%2A>, <xref:Microsoft.Extensions.Azure.BlobClientBuilderExtensions.AddBlobServiceClient%2A> and <xref:Microsoft.Extensions.Azure.ServiceBusClientBuilderExtensions.AddServiceBusClientWithNamespace%2A>, 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.
61-
* <xref:Azure.Identity.DefaultAzureCredential> is used to satisfy the `TokenCredential` argument requirement for each registered client. When one of the clients is created, `DefaultAzureCredential` is used to authenticate.
61+
* Each registered client automatically uses <xref:Azure.Identity.DefaultAzureCredential> for `TokenCredential` unless you configure a different type of credential (for example, using `WithCredential`).
6262
* 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.
6363
* An Azure OpenAI client is registered using a custom client factory via the <xref:Microsoft.Extensions.Azure.AzureClientFactoryBuilder.AddClient%2A> method, which provides control over how a client instance is created. Custom client factories are useful in the following cases:
6464
* You need to use other dependencies during the client construction.
@@ -145,8 +145,6 @@ builder.Services.AddAzureClients(clientBuilder =>
145145
clientBuilder.AddServiceBusClientWithNamespace(
146146
builder.Configuration["ServiceBus:Namespace"]);
147147

148-
clientBuilder.UseCredential(new DefaultAzureCredential());
149-
150148
// Set up any default settings
151149
clientBuilder.ConfigureDefaults(
152150
builder.Configuration.GetSection("AzureDefaults"));
@@ -167,8 +165,6 @@ builder.Services.AddAzureClients(clientBuilder =>
167165
clientBuilder.AddServiceBusClientWithNamespace(
168166
builder.Configuration["ServiceBus:Namespace"]);
169167

170-
clientBuilder.UseCredential(new DefaultAzureCredential());
171-
172168
// Set up any default settings
173169
clientBuilder.ConfigureDefaults(
174170
builder.Configuration.GetSection("AzureDefaults"));
@@ -193,8 +189,6 @@ IHost host = Host.CreateDefaultBuilder(args)
193189
clientBuilder.AddServiceBusClientWithNamespace(
194190
hostContext.Configuration["ServiceBus:Namespace"]);
195191

196-
clientBuilder.UseCredential(new DefaultAzureCredential());
197-
198192
// Set up any default settings
199193
clientBuilder.ConfigureDefaults(
200194
hostContext.Configuration.GetSection("AzureDefaults"));
@@ -211,7 +205,7 @@ In the preceding JSON sample:
211205
* The `AzureDefaults.Retry` object literal:
212206
* Represents the [retry policy configuration settings](#configure-a-new-retry-policy).
213207
* Corresponds to the <xref:Azure.Core.ClientOptions.Retry> property. Within that object literal, you find the `MaxRetries` key, which corresponds to the <xref:Azure.Core.RetryOptions.MaxRetries> property.
214-
* The `KeyVault:VaultUri`, `ServiceBus:Namespace`, and `Storage:ServiceUri` key values map to the `Uri`- and `string`-typed arguments of the <xref:Azure.Security.KeyVault.Secrets.SecretClient.%23ctor(System.Uri,Azure.Core.TokenCredential,Azure.Security.KeyVault.Secrets.SecretClientOptions)?displayProperty=fullName>, <xref:Azure.Messaging.ServiceBus.ServiceBusClient.%23ctor(System.String)?displayProperty=fullName>, and <xref:Azure.Storage.Blobs.BlobServiceClient.%23ctor(System.Uri,Azure.Core.TokenCredential,Azure.Storage.Blobs.BlobClientOptions)?displayProperty=fullName> constructor overloads, respectively. The `TokenCredential` variants of the constructors are used because a default `TokenCredential` is set via the <xref:Microsoft.Extensions.Azure.AzureClientFactoryBuilder.UseCredential(Azure.Core.TokenCredential)?displayProperty=fullName> method call.
208+
* The `KeyVault:VaultUri`, `ServiceBus:Namespace`, and `Storage:ServiceUri` key values map to the `Uri`- and `string`-typed arguments of the <xref:Azure.Security.KeyVault.Secrets.SecretClient.%23ctor(System.Uri,Azure.Core.TokenCredential,Azure.Security.KeyVault.Secrets.SecretClientOptions)?displayProperty=fullName>, <xref:Azure.Messaging.ServiceBus.ServiceBusClient.%23ctor(System.String)?displayProperty=fullName>, and <xref:Azure.Storage.Blobs.BlobServiceClient.%23ctor(System.Uri,Azure.Core.TokenCredential,Azure.Storage.Blobs.BlobClientOptions)?displayProperty=fullName> constructor overloads, respectively.
215209

216210
## Configure multiple service clients with different names
217211

@@ -283,7 +277,6 @@ builder.Services.AddAzureClients(clientBuilder =>
283277
// Establish the global defaults
284278
clientBuilder.ConfigureDefaults(
285279
builder.Configuration.GetSection("AzureDefaults"));
286-
clientBuilder.UseCredential(new DefaultAzureCredential());
287280

288281
// A Key Vault Secrets client using the global defaults
289282
clientBuilder.AddSecretClient(

docs/azure/sdk/logging.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,6 @@ Using the Azure Service Bus library as an example, complete the following steps:
139139
{
140140
azureBuilder.AddServiceBusClient(
141141
builder.Configuration.GetConnectionString("ServiceBus"));
142-
azureBuilder.UseCredential(new DefaultAzureCredential());
143142
});
144143
```
145144
@@ -148,7 +147,7 @@ Using the Azure Service Bus library as an example, complete the following steps:
148147
- Registers the following objects with the dependency injection (DI) container:
149148
- Log forwarder service
150149
- Azure Service Bus client
151-
- Sets the default token credential to be used for all registered clients.
150+
- Applies <xref:Azure.Identity.DefaultAzureCredential> automatically for authentication unless a different credential is explicitly configured.
152151
153152
1. In *appsettings.json*, change the Service Bus library's default log level. For example, toggle it to `Debug` by setting the `Logging:LogLevel:Azure.Messaging.ServiceBus` key as follows:
154153

docs/azure/sdk/snippets/aspnetcore-guidance/BlazorSample/Program.cs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,6 @@
2424
(_, _, provider) => provider.GetService<ServiceBusClient>()
2525
.CreateSender(queue)).WithName(queue);
2626
}
27-
28-
// Register a shared credential for Microsoft Entra ID authentication
29-
clientBuilder.UseCredential(new DefaultAzureCredential());
3027
});
3128

3229
var app = builder.Build();

docs/azure/sdk/snippets/aspnetcore-guidance/MinApiSample/Program.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,6 @@
3333
.CreateSender(queue)).WithName(queue);
3434
}
3535

36-
clientBuilder.UseCredential(new DefaultAzureCredential());
37-
3836
// Set up any default settings
3937
clientBuilder.ConfigureDefaults(
4038
builder.Configuration.GetSection("AzureDefaults"));

docs/azure/sdk/snippets/authentication/credential-chains/Program.cs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,6 @@
2626
new Uri($"https://{keyVaultName}.vault.azure.net"));
2727
clientBuilder.AddBlobServiceClient(
2828
new Uri($"https://{storageAccountName}.blob.core.windows.net"));
29-
30-
DefaultAzureCredential credential = new();
31-
clientBuilder.UseCredential(credential);
3229
});
3330
#endregion snippet_Dac
3431

docs/azure/sdk/snippets/authentication/local-dev-account/Program.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,6 @@ void registerUsingServicePrincipal(WebApplicationBuilder builder)
5050
{
5151
clientBuilder.AddBlobServiceClient(
5252
new Uri("https://<account-name>.blob.core.windows.net"));
53-
54-
clientBuilder.UseCredential(new DefaultAzureCredential());
5553
});
5654
#endregion snippet_DefaultAzureCredential_UseCredential
5755

docs/azure/sdk/snippets/dependency-injection/HostApplicationBuilder/Program.cs

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,26 +15,28 @@
1515
clientBuilder.AddBlobServiceClient(new Uri("<storage_url>"));
1616
clientBuilder.AddServiceBusClientWithNamespace("<your_namespace>.servicebus.windows.net");
1717

18-
// Set a credential for all clients to use by default
18+
// AddAzureClients implicitly creates a DefaultAzureCredential instance
19+
// Create a credential manually to override the type or access it explicitly for DI registrations
20+
// This example shows credential reuse for GetQueueNames and AddClient calls downstream
1921
DefaultAzureCredential credential = new();
2022
clientBuilder.UseCredential(credential);
2123

22-
// Register subclients for Service Bus
24+
// Register a subclient for each Service Bus Queue
2325
List<string> queueNames = await GetQueueNames(credential);
2426
foreach (string queueName in queueNames)
2527
{
2628
clientBuilder.AddClient<ServiceBusSender, ServiceBusClientOptions>((_, _, provider) =>
27-
provider.GetService(typeof(ServiceBusClient)) switch
28-
{
29-
ServiceBusClient client => client.CreateSender(queueName),
30-
_ => throw new InvalidOperationException("Unable to create ServiceBusClient")
31-
}).WithName(queueName);
29+
provider.GetService(typeof(ServiceBusClient)) switch
30+
{
31+
ServiceBusClient client => client.CreateSender(queueName),
32+
_ => throw new InvalidOperationException("Unable to create ServiceBusClient")
33+
}).WithName(queueName);
3234
}
3335

3436
// Register a custom client factory
3537
clientBuilder.AddClient<AzureOpenAIClient, AzureOpenAIClientOptions>(
36-
(options, _, _) => new AzureOpenAIClient(
37-
new Uri("<url_here>"), credential, options));
38+
(options, credential, _) => new AzureOpenAIClient(
39+
new Uri("<url_here>"), credential, options));
3840
});
3941
}).Build();
4042

docs/azure/sdk/snippets/dependency-injection/HostBuilder/Program.cs

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,23 +15,28 @@
1515
clientBuilder.AddBlobServiceClient(new Uri("<storage_url>"));
1616
clientBuilder.AddServiceBusClientWithNamespace("<your_namespace>.servicebus.windows.net");
1717

18-
// Set a credential for all clients to use by default
18+
// AddAzureClients implicitly creates a DefaultAzureCredential instance
19+
// Create a credential manually to override the type or access it explicitly for DI registrations
20+
// This example shows credential reuse for GetQueueNames and AddClient calls downstream
1921
DefaultAzureCredential credential = new();
2022
clientBuilder.UseCredential(credential);
21-
23+
2224
// Register a subclient for each Service Bus Queue
2325
List<string> queueNames = await GetQueueNames(credential);
24-
foreach (string queue in queueNames)
26+
foreach (string queueName in queueNames)
2527
{
2628
clientBuilder.AddClient<ServiceBusSender, ServiceBusClientOptions>((_, _, provider) =>
27-
provider.GetService<ServiceBusClient>().CreateSender(queue)
28-
).WithName(queue);
29+
provider.GetService(typeof(ServiceBusClient)) switch
30+
{
31+
ServiceBusClient client => client.CreateSender(queueName),
32+
_ => throw new InvalidOperationException("Unable to create ServiceBusClient")
33+
}).WithName(queueName);
2934
}
3035

3136
// Register a custom client factory
3237
clientBuilder.AddClient<AzureOpenAIClient, AzureOpenAIClientOptions>(
33-
(options, _, _) => new AzureOpenAIClient(
34-
new Uri("<url_here>"), credential, options));
38+
(options, credential, _) => new AzureOpenAIClient(
39+
new Uri("<url_here>"), credential, options));
3540
});
3641
}).Build();
3742

0 commit comments

Comments
 (0)