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 Azure 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 Azure.AI.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 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;
}

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 .
  • DefaultAzureCredential wordt gebruikt om te voldoen aan de TokenCredential argumentvereiste voor elke geregistreerde client. Wanneer een van de clients wordt gemaakt, DefaultAzureCredential wordt gebruikt om te verifiëren.
  • 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 Azure OpenAI-client wordt geregistreerd met behulp van een aangepaste clientfactory via de AddClient methode, die controle biedt over de manier waarop een clientexemplaren worden 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"]);

    clientBuilder.UseCredential(new DefaultAzureCredential());

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

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