Inserimento delle dipendenze con Azure SDK per .NET

Questo articolo illustra come registrare i client del servizio di Azure dalle librerie client di Azure più recenti per .NET per l'inserimento delle dipendenze in un'app .NET. Ogni app .NET moderna viene avviata usando le istruzioni fornite in un file Program.cs.

Installare i pacchetti

Per registrare e configurare i client del servizio da un pacchetto con prefisso-Azure.:

  1. Installare il pacchetto Microsoft.Extensions.Azure nel progetto:

    dotnet add package Microsoft.Extensions.Azure
    
  2. Installare il pacchetto Azure.Identity per configurare un tipo TokenCredential da usare per l'autenticazione di tutti i client registrati che accettano tale tipo:

    dotnet add package Azure.Identity
    

A scopo dimostrativo, il codice di esempio in questo articolo usa le librerie di segreti, Archiviazione BLOB e bus di servizio dell'insieme di credenziali delle chiavi. Installare i pacchetti seguenti per seguire questa procedura:

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

Registrare client e sottoclient

Un client di servizio è il punto di ingresso dell'API per un servizio di Azure, da cui gli utenti della libreria possono richiamare tutte le operazioni fornite dal servizio e possono implementare facilmente gli scenari più comuni. Per semplificare la progettazione di un'API, i gruppi di chiamate di servizio possono essere organizzati in base a tipi di sottoclient più piccoli. Ad esempio, ServiceBusClient può registrare ServiceBusSender sottoclient aggiuntivi per la pubblicazione di messaggi o ServiceBusReceiver sottoclient per l'utilizzo dei messaggi.

Nel file Program.cs, richiamare il metodo di estensione AddAzureClients per registrare un client per ogni servizio. Gli esempi di codice seguenti forniscono indicazioni sui generatori di applicazioni dagli spazi dei nomi Microsoft.AspNetCore.Builder e Microsoft.Extensions.Hosting.

using Azure.Identity;
using Azure.Messaging.ServiceBus;
using Azure.Messaging.ServiceBus.Administration;
using Microsoft.Extensions.Azure;

WebApplicationBuilder builder = WebApplication.CreateBuilder(args);

List<string> queueNames = await GetQueueNames();

builder.Services.AddAzureClients(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");
    clientBuilder.UseCredential(new DefaultAzureCredential());

    // Register a subclient for each Service Bus Queue
    foreach (string queue in queueNames)
    {
        clientBuilder.AddClient<ServiceBusSender, ServiceBusClientOptions>(
            (_, _, provider) => provider.GetService<ServiceBusClient>()
                    .CreateSender(queue)).WithName(queue);
    }
});

WebApplication app = builder.Build();

async Task<List<string>> GetQueueNames()
{
    // Query the available queues for the Service Bus namespace.
    var adminClient = new ServiceBusAdministrationClient
        ("<your_namespace>.servicebus.windows.net", new DefaultAzureCredential());
    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;
}

Nel codice precedente:

  • I segreti dell'insieme di credenziali delle chiavi, l'archiviazione BLOB e i client bus di servizio vengono registrati rispettivamente usando AddSecretClient, AddBlobServiceClient e AddServiceBusClientWithNamespace. Gli argomenti tipizzati Uri e string vengono passati. Per evitare di specificare questi URL in modo esplicito, vedere la sezione Archiviare configurazione separatamente dal codice.
  • DefaultAzureCredential viene usato per soddisfare il requisito dell'argomento TokenCredential per ogni client registrato. Quando viene creato uno dei client, DefaultAzureCredential viene usato per l'autenticazione.
  • I sottoclient del bus di servizio vengono registrati per ogni coda nel servizio usando il sottoclient e i tipi di opzione corrispondenti. I nomi delle code per i sottoclient vengono recuperati usando un metodo separato all'esterno della registrazione del servizio perché il metodo GetQueuesAsync deve essere eseguito in modo asincrono.

Usare i client registrati

Dopo aver registrato i client, come descritto nella sezione Registrare client e sottoclient, è ora possibile usarli. Nell'esempio seguente viene usato l'inserimento del costruttore per ottenere il client archiviazione BLOB in un controller API ASP.NET Core:

[ApiController]
[Route("[controller]")]
public class MyApiController : ControllerBase
{
    private readonly BlobServiceClient _blobServiceClient;
  
    public MyApiController(BlobServiceClient blobServiceClient)
    {
        _blobServiceClient = blobServiceClient;
    }
  
    [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();
    }
}

Archiviare configurazione separatamente dal codice

Nella sezione Registrare client e sottoclient sono state passate in modo esplicito le variabili tipizzata Uri ai costruttori client. Questo approccio può causare problemi quando si esegue codice in ambienti diversi durante lo sviluppo e la produzione. Il team .NET suggerisce di archiviare tali configurazioni nei file JSON dipendenti dall'ambiente. Ad esempio, è possibile avere un file appsettings.Development.json contenente le impostazioni dell'ambiente di sviluppo. Un altro file appsettings.Production.json conterrà le impostazioni dell'ambiente di produzione e così via. Il formato di file è:

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

È possibile aggiungere qualsiasi proprietà dalla classe ClientOptions nel file JSON. Le impostazioni nel file di configurazione JSON possono essere recuperate usando 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"));
});

Nel campione JSON precedente:

Configurare più client di servizio con nomi diversi

Si supponga di avere due account di archiviazione: uno per le informazioni private e un altro per le informazioni pubbliche. L'app trasferisce i dati dal pubblico all'account di archiviazione privato dopo un'operazione. È necessario avere due client del servizio di archiviazione. Per distinguere questi due client, usare il metodo di estensione WithName:

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

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

Usando un controller ASP.NET Core come esempio, accedere al client del servizio denominato usando l'interfaccia 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");
    }
}

Il client del servizio senza nome è ancora disponibile nello stesso modo di prima. I client denominati sono incrementali.

Configurare un nuovo criterio di ripetizione

A un certo punto, è possibile modificare le impostazioni predefinite per un client del servizio. Ad esempio, è possibile che si vogliano impostazioni di ripetizione diverse o usare una versione diversa dell'API del servizio. È possibile impostare le impostazioni di ripetizione a livello globale o in base al servizio. Si supponga di avere il file appsettings.json nel progetto ASP.NET Core:

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

È possibile modificare i criteri di ripetizione in base alle proprie esigenze, ad esempio:

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

È anche possibile inserire override dei criteri di ripetizione nel file appsettings.json:

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

Vedi anche