Abhängigkeitsinjektion mit dem Azure SDK für .NET
Dieser Artikel zeigt, wie Sie Azure-Dienstclients aus den neuesten Azure-Clientbibliotheken für .NET für die Injektion von Abhängigkeiten in einer .NET-Anwendung registrieren. Jede moderne .NET-Anwendung wird anhand der Anweisungen in einer Program.cs-Datei gestartet.
Installieren von Paketen
So registrieren und konfigurieren Sie Dienstclients aus einem Paket mit Präfix Azure.
:
Installieren Sie das Microsoft.Extensions.Azure-Paket in Ihrem Projekt:
dotnet add package Microsoft.Extensions.Azure
Installieren Sie das Azure.Identity-Paket, um einen
TokenCredential
-Typ für die Authentifizierung aller registrierten Clients zu konfigurieren, die einen solchen Typ akzeptieren:dotnet add package Azure.Identity
Zu Demonstrationszwecken verwendet der Beispielcode in diesem Artikel die Schlüsseltresorgeheimnisse, Blob Storage, Service Bus und Azure OpenAI-Bibliotheken. Installieren Sie die folgenden Pakete, um dem Beispiel zu folgen:
dotnet add package Azure.Security.KeyVault.Secrets
dotnet add package Azure.Storage.Blobs
dotnet add package Azure.Messaging.ServiceBus
dotnet add package Azure.AI.OpenAI
Registrieren von Clients und Unterclients
Ein Dienstclient ist der Einstiegspunkt für die API für einen Azure-Dienst – von dort aus können Bibliotheksbenutzer alle vom Dienst bereitgestellten Vorgänge aufrufen und die am häufigsten verwendeten Szenarien problemlos implementieren. Wo es das Design einer API vereinfacht, können Gruppen von Dienstaufrufen um kleinere Unterclienttypen organisiert werden. Beispielsweise kann ServiceBusClient
zusätzliche ServiceBusSender
-Unterclients zum Veröffentlichen von Nachrichten oder ServiceBusReceiver
-Unterclients für die Verwendung von Nachrichten registrieren.
Rufen Sie in der Datei Program.cs die Erweiterungsmethode AddAzureClients auf, um einen Client für jeden Dienst zu registrieren. Die folgenden Codebeispiele enthalten Anleitungen zu Anwendungserstellern aus den Namespaces Microsoft.AspNetCore.Builder
und Microsoft.Extensions.Hosting
.
using Azure.Identity;
using Azure.Messaging.ServiceBus;
using Azure.Messaging.ServiceBus.Administration;
using Microsoft.Extensions.Azure;
using Azure.AI.OpenAI;
WebApplicationBuilder builder = WebApplication.CreateBuilder(args);
builder.Services.AddAzureClients(async clientBuilder =>
{
// Register clients for each service
clientBuilder.AddSecretClient(new Uri("<key_vault_url>"));
clientBuilder.AddBlobServiceClient(new Uri("<storage_url>"));
clientBuilder.AddServiceBusClientWithNamespace(
"<your_namespace>.servicebus.windows.net");
// Set a credential for all clients to use by default
DefaultAzureCredential credential = new();
clientBuilder.UseCredential(credential);
// Register a subclient for each Service Bus Queue
List<string> queueNames = await GetQueueNames(credential);
foreach (string queue in queueNames)
{
clientBuilder.AddClient<ServiceBusSender, ServiceBusClientOptions>(
(_, _, provider) => provider.GetService<ServiceBusClient>()
.CreateSender(queue)).WithName(queue);
}
// Register a custom client factory
clientBuilder.AddClient<AzureOpenAIClient, AzureOpenAIClientOptions>(
(options, _, _) => new AzureOpenAIClient(
new Uri("<url_here>"), credential, options));
});
WebApplication app = builder.Build();
async Task<List<string>> GetQueueNames(DefaultAzureCredential credential)
{
// Query the available queues for the Service Bus namespace.
var adminClient = new ServiceBusAdministrationClient
("<your_namespace>.servicebus.windows.net", credential);
var queueNames = new List<string>();
// 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);
}
return queueNames;
}
Für den Code oben gilt:
- Key Vault Secrets- und Blob Storage- und Service Bus-Clients werden mit AddSecretClient, AddBlobServiceClient und AddServiceBusClientWithNamespace registriert. Die
Uri
- undstring
-Typargumente werden übergeben. Um zu vermeiden, dass Sie diese URLs explizit angeben, lesen Sie den Abschnitt Konfiguration getrennt vom Code speichern. - DefaultAzureCredential wird verwendet, um die Argumentanforderung
TokenCredential
für jeden registrierten Client zu erfüllen. Wenn einer der Clients erstellt wird, wirdDefaultAzureCredential
für die Authentifizierung verwendet. - Service Bus-Unterclients werden für jede Warteschlange im Dienst mithilfe des Unterclients und der entsprechenden Optionstypen registriert. Die Warteschlangennamen für die Unterclients werden mithilfe einer separaten Methode außerhalb der Dienstregistrierung abgerufen, da die
GetQueuesAsync
-Methode asynchron ausgeführt werden muss. - Ein Azure OpenAI-Client wird mithilfe einer benutzerdefinierten Clientfactory über die AddClient Methode registriert, die kontrolle darüber bietet, wie eine Clientinstanz erstellt wird. Benutzerdefinierte Client-Fabriken sind in den folgenden Fällen nützlich:
- Sie müssen während der Clienterstellung andere Abhängigkeiten verwenden.
- Für den Dienstclient, den Sie registrieren möchten, ist keine Registrierungserweiterungsmethode vorhanden.
Verwenden der registrierten Clients
Wenn die Clients registriert sind, wie im Abschnitt Clients und Unterclients registrieren beschrieben, können Sie sie jetzt verwenden. Im folgenden Beispiel wird Konstruktoreinfügung verwendet, um den Blob Storage-Client und eine Factory für Subclients von Service Bus-Sender in einem API-Controller von ASP.NET Core abzurufen:
[ApiController]
[Route("[controller]")]
public class MyApiController : ControllerBase
{
private readonly BlobServiceClient _blobServiceClient;
private readonly ServiceBusSender _serviceBusSender;
public MyApiController(
BlobServiceClient blobServiceClient,
IAzureClientFactory<ServiceBusSender> senderFactory)
{
_blobServiceClient = blobServiceClient;
_serviceBusSender = senderFactory.CreateClient("myQueueName");
}
[HttpGet]
public async Task<IEnumerable<string>> Get()
{
BlobContainerClient containerClient =
_blobServiceClient.GetBlobContainerClient("demo");
var results = new List<string>();
await foreach (BlobItem blob in containerClient.GetBlobsAsync())
{
results.Add(blob.Name);
}
return results.ToArray();
}
}
Speichern der Konfiguration getrennt vom Code
Im Abschnitt Clients und Unterclients registrieren haben Sie die Uri
-Typvariablen explizit an die Clientkonstruktoren übergeben. Dieser Ansatz kann Probleme verursachen, wenn Sie während der Entwicklung und Produktion Code für verschiedene Umgebungen ausführen. Das .NET-Team empfiehlt, solche Konfigurationen in umgebungsabhängigen JSON-Dateien zu speichern. Beispielsweise können Sie eine Datei namens appsettings.Development.json anlegen, die Einstellungen für die Entwicklungsumgebung enthält. Eine weitere Datei namens appsettings.Production.json würde Einstellungen für die Produktionsumgebung enthalten. Das Dateiformat ist:
{
"AzureDefaults": {
"Diagnostics": {
"IsTelemetryDisabled": false,
"IsLoggingContentEnabled": true
},
"Retry": {
"MaxRetries": 3,
"Mode": "Exponential"
}
},
"KeyVault": {
"VaultUri": "https://mykeyvault.vault.azure.net"
},
"ServiceBus": {
"Namespace": "<your_namespace>.servicebus.windows.net"
},
"Storage": {
"ServiceUri": "https://mydemoaccount.storage.windows.net"
}
}
Sie können der JSON-Datei beliebige Eigenschaften aus der ClientOptions-Klasse hinzufügen. Die Einstellungen in der JSON-Konfigurationsdatei können mit IConfiguration abgerufen werden.
builder.Services.AddAzureClients(clientBuilder =>
{
clientBuilder.AddSecretClient(
builder.Configuration.GetSection("KeyVault"));
clientBuilder.AddBlobServiceClient(
builder.Configuration.GetSection("Storage"));
clientBuilder.AddServiceBusClientWithNamespace(
builder.Configuration["ServiceBus:Namespace"]);
clientBuilder.UseCredential(new DefaultAzureCredential());
// Set up any default settings
clientBuilder.ConfigureDefaults(
builder.Configuration.GetSection("AzureDefaults"));
});
Im vorherigen JSON-Beispiel:
- Die Schlüsselnamen der obersten Ebene (
AzureDefaults
,KeyVault
,ServiceBus
undStorage
) sind beliebig. Alle anderen Schlüsselnamen sind von Bedeutung. Bei der JSON-Serialisierung wird die Groß- und Kleinschreibung nicht berücksichtigt. - Das Objektliteral
AzureDefaults.Retry
:- Stellt die Konfigurationseinstellungen für Wiederholungsrichtlinien dar.
- Entspricht der Retry-Eigenschaft. Innerhalb dieses Objektliterals finden Sie den Schlüssel
MaxRetries
, der der Eigenschaft MaxRetries entspricht.
- Die Schlüsselwerte
KeyVault:VaultUri
,ServiceBus:Namespace
undStorage:ServiceUri
werden denUri
- undstring
-Typargumenten der Konstruktorüberladungen Azure.Security.KeyVault.Secrets.SecretClient.SecretClient(Uri, TokenCredential, SecretClientOptions), Azure.Messaging.ServiceBus.ServiceBusClient.ServiceBusClient(String) und Azure.Storage.Blobs.BlobServiceClient.BlobServiceClient(Uri, TokenCredential, BlobClientOptions) zugeordnet. DieTokenCredential
-Varianten der Konstruktoren werden verwendet, da ein StandardwertTokenCredential
über den Methodenaufruf Microsoft.Extensions.Azure.AzureClientFactoryBuilder.UseCredential(TokenCredential) festgelegt wird.
Konfigurieren mehrerer Dienstclients mit unterschiedlichen Namen
Angenommen, Sie verfügen über zwei Speicherkonten: eines für private Informationen und eines für öffentliche Informationen. Ihre App überträgt Daten nach einem Vorgang vom öffentlichen in das private Speicherkonto. Sie benötigen zwei Speicherdienstclients. Verwenden Sie die Erweiterungsmethode WithName, um diese beiden Clients zu unterscheiden:
builder.Services.AddAzureClients(clientBuilder =>
{
clientBuilder.AddBlobServiceClient(
builder.Configuration.GetSection("PublicStorage"));
clientBuilder.AddBlobServiceClient(
builder.Configuration.GetSection("PrivateStorage"))
.WithName("PrivateStorage");
});
Greifen Sie beispielsweise mithilfe eines ASP.NET Core-Controllers über die Schnittstelle IAzureClientFactory<TClient> auf den benannten Dienstclient zu:
public class HomeController : Controller
{
private readonly BlobServiceClient _publicStorage;
private readonly BlobServiceClient _privateStorage;
public HomeController(
BlobServiceClient defaultClient,
IAzureClientFactory<BlobServiceClient> clientFactory)
{
_publicStorage = defaultClient;
_privateStorage = clientFactory.CreateClient("PrivateStorage");
}
}
Der unbenannte Dienstclient ist weiterhin auf die gleiche Weise wie zuvor verfügbar. Benannte Clients sind additiv.
Konfigurieren einer neuen Wiederholungsrichtlinie
Vielleicht möchten Sie irgendwann die Standardeinstellungen für einen Dienstclient ändern. Sie möchten z. B. andere Wiederholungseinstellungen oder eine andere Version der Service-API verwenden. Sie können die Wiederholungseinstellungen global oder dienstspezifisch festlegen. Angenommen, Sie haben die folgende Datei appsettings.json in Ihrem ASP.NET Core-Projekt:
{
"AzureDefaults": {
"Retry": {
"maxRetries": 3
}
},
"KeyVault": {
"VaultUri": "https://mykeyvault.vault.azure.net"
},
"ServiceBus": {
"Namespace": "<your_namespace>.servicebus.windows.net"
},
"Storage": {
"ServiceUri": "https://store1.storage.windows.net"
},
"CustomStorage": {
"ServiceUri": "https://store2.storage.windows.net"
}
}
Sie können die Wiederholungsrichtlinie wie folgt an Ihre Bedürfnisse anpassen:
builder.Services.AddAzureClients(clientBuilder =>
{
// Establish the global defaults
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"));
// A Blob Storage client with a custom retry policy
clientBuilder.AddBlobServiceClient(
builder.Configuration.GetSection("Storage"))
.ConfigureOptions(options => options.Retry.MaxRetries = 10);
clientBuilder.AddServiceBusClientWithNamespace(
builder.Configuration["ServiceBus:Namespace"])
.ConfigureOptions(options => options.RetryOptions.MaxRetries = 10);
// A named storage client with a different custom retry policy
clientBuilder.AddBlobServiceClient(
builder.Configuration.GetSection("CustomStorage"))
.WithName("CustomStorage")
.ConfigureOptions(options =>
{
options.Retry.Mode = Azure.Core.RetryMode.Exponential;
options.Retry.MaxRetries = 5;
options.Retry.MaxDelay = TimeSpan.FromSeconds(120);
});
});
Sie können Richtlinienüberschreibungen auch in der Datei appsettings.json speichern:
{
"KeyVault": {
"VaultUri": "https://mykeyvault.vault.azure.net",
"Retry": {
"maxRetries": 10
}
}
}