Udostępnij za pośrednictwem


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:

  1. Zainstaluj pakiet Microsoft.Extensions.Azure w projekcie:

    dotnet add package Microsoft.Extensions.Azure
    
  2. 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- i string-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 utworzeniu DefaultAzureCredential 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 Urizmienne 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:

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
    }
  }
}

Zobacz też