Delen via


Afhankelijkheidsinjectie met de Azure SDK voor .NET

In dit artikel wordt beschreven hoe u Azure-serviceclients registreert uit de nieuwste Azure-clientbibliotheken voor .NET voor afhankelijkheidsinjectie in een .NET-app. Elke moderne .NET-app wordt gestart met behulp van de instructies in een Program.cs-bestand .

Pakketten installeren

Serviceclients registreren en configureren vanuit een Azure.-voorvoegselpakket:

  1. Installeer het pakket Microsoft.Extensions.Azure in uw project:

    dotnet add package Microsoft.Extensions.Azure
    
  2. Installeer het Azure.Identity-pakket om een TokenCredential type te configureren dat moet worden gebruikt voor het verifiëren van alle geregistreerde clients die een dergelijk type accepteren:

    dotnet add package Azure.Identity
    

Voor demonstratiedoeleinden gebruikt de voorbeeldcode in dit artikel de Key Vault-geheimen, Blob Storage-, Service Bus- en OpenAI-bibliotheken. Installeer de volgende pakketten om mee te doen:

dotnet add package Azure.Security.KeyVault.Secrets
dotnet add package Azure.Storage.Blobs
dotnet add package Azure.Messaging.ServiceBus
dotnet add package OpenAI

Clients en subclients registreren

Een serviceclient is het toegangspunt voor de API voor een Azure-service: bibliotheekgebruikers kunnen alle bewerkingen die de service biedt aanroepen en kunnen eenvoudig de meest voorkomende scenario's implementeren. Waar het ontwerp van een API wordt vereenvoudigd, kunnen groepen serviceaanroepen worden georganiseerd rond kleinere subclienttypen. U kunt bijvoorbeeld ServiceBusClient extra ServiceBusSender subclients registreren voor het publiceren van berichten of ServiceBusReceiver subclients voor het gebruiken van berichten.

Roep in het Program.cs-bestand de AddAzureClients extensiemethode aan om een client voor elke service te registreren. De volgende codevoorbeelden bieden richtlijnen voor toepassingsbouwers uit de Microsoft.AspNetCore.Builder en Microsoft.Extensions.Hosting naamruimten.

using Azure.Identity;
using Azure.Messaging.ServiceBus;
using Azure.Messaging.ServiceBus.Administration;
using Microsoft.Extensions.Azure;
using OpenAI;
using OpenAI.Responses;
using System.ClientModel.Primitives;

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");
    
    // AddAzureClients implicitly creates a DefaultAzureCredential instance
    // Create a credential manually to override the type or access it explicitly for DI registrations
    // This example shows credential reuse for GetQueueNames and AddClient calls downstream
    DefaultAzureCredential credential = new();
    clientBuilder.UseCredential(credential);

    // Register a subclient for each Service Bus Queue
    List<string> queueNames = await GetQueueNames(credential);
    foreach (string queueName in queueNames)
    {
        clientBuilder.AddClient<ServiceBusSender, ServiceBusClientOptions>((_, _, provider) =>
            provider.GetService(typeof(ServiceBusClient)) switch
            {
                ServiceBusClient client => client.CreateSender(queueName),
                _ => throw new InvalidOperationException("Unable to create ServiceBusClient")
            }).WithName(queueName);
    }

    var endpoint = Environment.GetEnvironmentVariable("AZURE_OPENAI_ENDPOINT")
        ?? throw new InvalidOperationException("AZURE_OPENAI_ENDPOINT is required.");

    // Register a custom client factory
    #pragma warning disable OPENAI001 // Type is for evaluation purposes and is subject to change in future updates.
    clientBuilder.AddClient<ResponsesClient, OpenAIClientOptions>(
        (options, credential, _) => new ResponsesClient(
            "<deployment_name>",
            new BearerTokenPolicy(credential, "https://ai.azure.com/.default"),
            new OpenAIClientOptions { Endpoint = new Uri($"{endpoint}/openai/v1/") }
        ));
    #pragma warning restore OPENAI001
});

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

In de voorgaande code:

  • Key Vault-geheimen, Blob Storage- en Service Bus-clients worden geregistreerd met respectievelijk de AddSecretClient, AddBlobServiceClient en AddServiceBusClientWithNamespace. De Uriargumenten - en string-getypt worden doorgegeven. Als u wilt voorkomen dat u deze URL's expliciet opgeeft, raadpleegt u de Store-configuratie afzonderlijk van de codesectie .
  • Elke geregistreerde client gebruikt DefaultAzureCredential automatisch voor TokenCredential , tenzij u een ander type referentie configureert (bijvoorbeeld met behulp van WithCredential).
  • Service Bus-subclients worden geregistreerd voor elke wachtrij op de service met behulp van de subclient en de bijbehorende optiestypen. De wachtrijnamen voor de subclients worden opgehaald met behulp van een afzonderlijke methode buiten de serviceregistratie, omdat de GetQueuesAsync methode asynchroon moet worden uitgevoerd.
  • Een ResponsesClient wordt geregistreerd met behulp van een aangepaste client-factory via de AddClient methode, die controle biedt over hoe een clientexemplaar wordt gemaakt. Aangepaste client factory's zijn handig in de volgende gevallen:
    • U moet andere afhankelijkheden gebruiken tijdens de clientconstructie.
    • Er bestaat geen registratieextensiemethode voor de serviceclient die u wilt registreren.

De geregistreerde clients gebruiken

Als de clients zijn geregistreerd, zoals beschreven in de sectie Clients en subclients registreren, kunt u deze nu gebruiken. In het volgende voorbeeld wordt constructorinjectie gebruikt voor het verkrijgen van de Blob Storage-client en een factory voor Service Bus-afzendersubclients in een ASP.NET Core API-controller:

[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();
    }
}

Configuratie afzonderlijk van code opslaan

In de sectie Clients en subclients registreren hebt u de Uridoor u getypte variabelen expliciet doorgegeven aan de clientconstructors. Deze aanpak kan problemen veroorzaken wanneer u tijdens de ontwikkeling en productie code uitvoert op verschillende omgevingen. Het .NET-team stelt voor om dergelijke configuraties op te slaan in omgevingsafhankelijke JSON-bestanden. U kunt bijvoorbeeld appsettings hebben. Development.json bestand met instellingen voor de ontwikkelomgeving. Andere appsettings. Production.json bestand zou instellingen voor de productieomgeving bevatten, enzovoort. De bestandsindeling is:

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

U kunt alle eigenschappen uit de ClientOptions klasse toevoegen aan het JSON-bestand. De instellingen in het JSON-configuratiebestand kunnen worden opgehaald met behulp van IConfiguration.

builder.Services.AddAzureClients(clientBuilder =>
{
    clientBuilder.AddSecretClient(
        builder.Configuration.GetSection("KeyVault"));

    clientBuilder.AddBlobServiceClient(
        builder.Configuration.GetSection("Storage"));

    clientBuilder.AddServiceBusClientWithNamespace(
        builder.Configuration["ServiceBus:Namespace"]);

    // Set up any default settings
    clientBuilder.ConfigureDefaults(
        builder.Configuration.GetSection("AzureDefaults"));
});

In het voorgaande JSON-voorbeeld:

Meerdere serviceclients met verschillende namen configureren

Stel dat u twee opslagaccounts hebt: één voor persoonlijke gegevens en een andere voor openbare informatie. Uw app draagt gegevens over van het publiek naar het privéopslagaccount na een bepaalde bewerking. U moet twee opslagserviceclients hebben. Gebruik de WithName extensiemethode om onderscheid te maken tussen deze twee clients:

builder.Services.AddAzureClients(clientBuilder =>
{
    clientBuilder.AddBlobServiceClient(
        builder.Configuration.GetSection("PublicStorage"));

    clientBuilder.AddBlobServiceClient(
            builder.Configuration.GetSection("PrivateStorage"))
        .WithName("PrivateStorage");
});

Als u een ASP.NET Core-controller als voorbeeld gebruikt, opent u de benoemde serviceclient met behulp van de IAzureClientFactory<TClient> interface:

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");
    }
}

De niet-benoemde serviceclient is nog steeds op dezelfde manier beschikbaar als voorheen. Benoemde clients zijn additief.

Een nieuw beleid voor opnieuw proberen configureren

Op een bepaald moment kunt u de standaardinstellingen voor een serviceclient wijzigen. U kunt bijvoorbeeld verschillende instellingen voor opnieuw proberen of een andere service-API-versie gebruiken. U kunt de instellingen voor opnieuw proberen globaal of per service instellen. Stel dat u het volgende appsettings.json-bestand in uw ASP.NET Core-project hebt:

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

U kunt het beleid voor opnieuw proberen zo aanpassen aan uw behoeften:

builder.Services.AddAzureClients(clientBuilder =>
{
    // Establish the global defaults
    clientBuilder.ConfigureDefaults(
        builder.Configuration.GetSection("AzureDefaults"));

    // 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);
        });
});

U kunt ook beleidsoverschrijvingen voor opnieuw proberen in het appsettings.json-bestand plaatsen:

{
  "KeyVault": {
    "VaultUri": "https://mykeyvault.vault.azure.net",
    "Retry": {
      "maxRetries": 10
    }
  }
}

Zie ook