Wstrzykiwanie zależności za pomocą zestawu Azure SDK dla platformy .NET
W tym artykule pokazano, jak zarejestrować klientów usługi platformy Azure z najnowszych bibliotek klienckich platformy Azure dla platformy .NET na potrzeby wstrzykiwania zależności w aplikacji .NET. Każda nowoczesna aplikacja .NET jest uruchamiana przy użyciu instrukcji podanych w pliku Program.cs .
Instalowanie pakietów
Aby zarejestrować i skonfigurować klientów usługi z prefiksu Azure.
pakietu:
Zainstaluj pakiet Microsoft.Extensions.Azure w projekcie:
dotnet add package Microsoft.Extensions.Azure
Zainstaluj pakiet Azure.Identity, aby skonfigurować
TokenCredential
typ używany do uwierzytelniania wszystkich zarejestrowanych klientów, którzy akceptują taki typ:dotnet add package Azure.Identity
W celach demonstracyjnych przykładowy kod w tym artykule używa wpisów tajnych usługi Key Vault, usługi Blob Storage, usługi Service Bus i bibliotek Azure OpenAI. Zainstaluj następujące pakiety, aby wykonać następujące czynności:
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
Rejestrowanie klientów i klientów podrzędnych
Klient usługi to punkt wejścia do interfejsu API dla usługi platformy Azure — z niego użytkownicy biblioteki mogą wywoływać wszystkie operacje zapewniane przez usługę i łatwo implementować najbardziej typowe scenariusze. W przypadku uproszczenia projektu interfejsu API grupy wywołań usług mogą być zorganizowane wokół mniejszych typów podrzędnych klientów. Na przykład ServiceBusClient
może zarejestrować dodatkowych ServiceBusSender
podrzędnych klientów do publikowania komunikatów lub ServiceBusReceiver
podrzędnych klientów na potrzeby korzystania z komunikatów.
W pliku Program.cs wywołaj metodę AddAzureClients rozszerzenia, aby zarejestrować klienta dla każdej usługi. Poniższe przykłady kodu zawierają wskazówki dotyczące konstruktorów aplikacji z Microsoft.AspNetCore.Builder
przestrzeni nazw i 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;
}
Powyższy kod:
- Wpisy tajne usługi Key Vault, usługa Blob Storage i klienci usługi Service Bus są zarejestrowani przy użyciu AddSecretClientodpowiednio poleceń i AddBlobServiceClient AddServiceBusClientWithNamespace. Argumenty
Uri
- istring
-typed są przekazywane. Aby uniknąć jawnego określania tych adresów URL, zobacz sekcję Konfiguracja magazynu oddzielnie od sekcji kodu . - DefaultAzureCredential służy do spełnienia wymagania argumentu dla każdego zarejestrowanego
TokenCredential
klienta. Po utworzeniuDefaultAzureCredential
jednego z klientów jest używany do uwierzytelniania. - Podklienci usługi Service Bus są rejestrowane dla każdej kolejki w usłudze przy użyciu podklienta i odpowiednich typów opcji. Nazwy kolejek dla podklienców są pobierane przy użyciu oddzielnej metody poza rejestracją usługi, ponieważ
GetQueuesAsync
metoda musi być uruchamiana asynchronicznie. - Klient usługi Azure OpenAI jest rejestrowany przy użyciu niestandardowej fabryki klienta za pośrednictwem AddClient metody , która zapewnia kontrolę nad sposobem tworzenia wystąpienia klienta. Niestandardowe fabryki klientów są przydatne w następujących przypadkach:
- Podczas budowy klienta należy używać innych zależności.
- Metoda rozszerzenia rejestracji nie istnieje dla klienta usługi, który chcesz zarejestrować.
Korzystanie z zarejestrowanych klientów
Po zarejestrowaniu klientów, zgodnie z opisem w sekcji Rejestrowanie klientów i podklienci , można ich teraz używać. W poniższym przykładzie iniekcja konstruktora służy do uzyskiwania klienta usługi Blob Storage i fabryki dla klientów podrzędnych nadawcy usługi Service Bus w kontrolerze interfejsu API platformy ASP.NET Core:
[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();
}
}
Przechowywanie konfiguracji oddzielnie od kodu
W sekcji Rejestrowanie klientów i podklienci jawnie przekazano Uri
zmienne typizowane do konstruktorów klienta. Takie podejście może powodować problemy podczas uruchamiania kodu w różnych środowiskach podczas programowania i produkcji. Zespół platformy .NET sugeruje przechowywanie takich konfiguracji w plikach JSON zależnych od środowiska. Na przykład możesz mieć ustawienia aplikacji. Development.json plik zawierający ustawienia środowiska deweloperskiego. Inne ustawienia aplikacji. Production.json plik zawiera ustawienia środowiska produkcyjnego itd. Format pliku to:
{
"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"
}
}
Do pliku JSON można dodać dowolne właściwości z ClientOptions klasy. Ustawienia w pliku konfiguracji JSON można pobrać przy użyciu polecenia IConfiguration.
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"));
});
W poprzednim przykładzie JSON:
- Nazwy kluczy najwyższego poziomu,
AzureDefaults
,KeyVault
,ServiceBus
iStorage
, są dowolne. Wszystkie inne nazwy kluczy mają znaczenie, a serializacja JSON jest wykonywana w sposób bez uwzględniania wielkości liter. - Literał
AzureDefaults.Retry
obiektu:- Reprezentuje ustawienia konfiguracji zasad ponawiania.
- Retry Odpowiada właściwości . W obrębie tego literału obiektu znajduje
MaxRetries
się klucz odpowiadający MaxRetries właściwości .
KeyVault:VaultUri
Wartości ,ServiceBus:Namespace
iStorage:ServiceUri
klucza są mapowane odpowiednio naUri
argumenty Azure.Security.KeyVault.Secrets.SecretClient.SecretClient(Uri, TokenCredential, SecretClientOptions)Azure.Messaging.ServiceBus.ServiceBusClient.ServiceBusClient(String)- istring
-typed przeciążeń , i Azure.Storage.Blobs.BlobServiceClient.BlobServiceClient(Uri, TokenCredential, BlobClientOptions) konstruktora. UżywaneTokenCredential
są warianty konstruktorów, ponieważ ustawienie domyślneTokenCredential
jest ustawiane za pośrednictwem wywołania Microsoft.Extensions.Azure.AzureClientFactoryBuilder.UseCredential(TokenCredential) metody.
Konfigurowanie wielu klientów usługi o różnych nazwach
Załóżmy, że masz dwa konta magazynu: jedno dla informacji prywatnych, a drugie dla informacji publicznych. Aplikacja przesyła dane z publicznego do prywatnego konta magazynu po operacji. Musisz mieć dwóch klientów usługi magazynu. Aby odróżnić tych dwóch klientów, użyj WithName metody rozszerzenia:
builder.Services.AddAzureClients(clientBuilder =>
{
clientBuilder.AddBlobServiceClient(
builder.Configuration.GetSection("PublicStorage"));
clientBuilder.AddBlobServiceClient(
builder.Configuration.GetSection("PrivateStorage"))
.WithName("PrivateStorage");
});
Korzystając z kontrolera ASP.NET Core jako przykładu, uzyskaj dostęp do nazwanego klienta usługi przy użyciu interfejsu IAzureClientFactory<TClient> :
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");
}
}
Nienazwany klient usługi jest nadal dostępny w taki sam sposób jak poprzednio. Nazwani klienci są dodatkiem.
Konfigurowanie nowych zasad ponawiania prób
W pewnym momencie możesz zmienić ustawienia domyślne klienta usługi. Na przykład możesz chcieć użyć różnych ustawień ponawiania prób lub użyć innej wersji interfejsu API usługi. Ustawienia ponawiania można ustawić globalnie lub dla poszczególnych usług. Załóżmy, że w projekcie ASP.NET Core masz następujący plik appsettings.json :
{
"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"
}
}
Możesz zmienić zasady ponawiania w taki sposób, aby odpowiadały twoim potrzebom:
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);
});
});
Można również umieścić przesłonięcia zasad ponawiania w pliku appsettings.json :
{
"KeyVault": {
"VaultUri": "https://mykeyvault.vault.azure.net",
"Retry": {
"maxRetries": 10
}
}
}