Partager via


Injection de dépendances avec le Kit de développement logiciel (SDK) Azure pour .NET

Cet article explique comment inscrire des clients de service Azure à partir des dernières bibliothèques clientes Azure pour .NET pour l’injection de dépendances dans une application .NET. Chaque application .NET moderne démarre à l’aide des instructions fournies dans un fichier Program.cs.

Installer des packages

Pour inscrire et configurer des clients de service à partir d’un package avec préfixe Azure. :

  1. Installez le package Microsoft.Extensions.Azure dans votre projet :

    dotnet add package Microsoft.Extensions.Azure
    
  2. Installez le package Azure.Identity pour configurer un type TokenCredential à utiliser pour authentifier tous les clients inscrits qui acceptent ce type :

    dotnet add package Azure.Identity
    

À des fins de démonstration, l’exemple de code de cet article utilise les bibliothèques Secrets Key Vault, Stockage Blob et Service Bus. Installez ensuite les packages suivants :

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

Inscrire des clients et des sous-clients

Un client de service est le point d’entrée de l’API d’un service Azure. À partir de celui-ci, les utilisateurs de bibliothèque peuvent appeler toutes les opérations que le service fournit et peuvent facilement implémenter les scénarios les plus courants. Pour simplifier la conception d’une API, les groupes d’appels de service peuvent être organisés en types de sous-clients plus petits. Par exemple, ServiceBusClient peut inscrire des sous-clients ServiceBusSender supplémentaires pour la publication des messages, ou des sous-clients ServiceBusReceiver pour la consommation des messages.

Dans le fichier Program.cs, appelez la méthode d’extension AddAzureClients pour inscrire un client pour chaque service. Les exemples de code suivants fournissent une aide sur les générateurs d’applications à partir des espaces de noms Microsoft.AspNetCore.Builder et 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;
}

Dans le code précédent :

  • Les clients Secrets Key Vault, Stockage Blob et Service Bus sont inscrits à l’aide de AddSecretClient, AddBlobServiceClient et AddServiceBusClientWithNamespace, respectivement. Les arguments de type Uri et string sont passés. Pour éviter de spécifier explicitement ces URL, consultez la section Stocker la configuration séparément du code.
  • DefaultAzureCredential est utilisé pour satisfaire l’exigence d’argument TokenCredential pour chaque client inscrit. Quand l’un des clients est créé, DefaultAzureCredential est utilisé pour l’authentification.
  • Les sous-clients de Service Bus sont inscrits pour chaque file d’attente du service à l’aide du sous-client et des types d’options correspondants. Les noms de files d’attente des sous-clients sont récupérés à l’aide d’une méthode distincte en dehors de l’inscription du service, car la méthode GetQueuesAsync doit être exécutée de manière asynchrone.

Utiliser les clients inscrits

Une fois les clients inscrits, comme indiqué dans la section Inscrire des clients et des sous-clients, vous pouvez désormais les utiliser. Dans l’exemple suivant, l’injection de constructeurr est utilisée pour obtenir le client Blob Storage et une fabrique de sous-clients d’expéditeur de bus de services dans un contrôleur API 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();
    }
}

Stocker la configuration séparément du code

Dans la section Inscrire des clients et des sous-clients, vous avez passé explicitement les variables de type Uri aux constructeurs clients. Cette approche peut entraîner des problèmes lorsque vous exécutez du code sur différents environnements pendant le développement et la production. L’équipe .NET suggère de stocker ces configurations dans des fichiers JSON dépendant de l’environnement. Par exemple, vous pouvez avoir un fichier appsettings.Development.json contenant les paramètres d’environnement de développement. Un autre fichier appsettings.Production.json contient des paramètres d’environnement de production, etc. Le format de fichier est :

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

Vous pouvez ajouter des propriétés de la classe ClientOptions dans le fichier JSON. Les paramètres du fichier de configuration JSON peuvent être récupérés à l’aide de 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"));
});

Dans l’exemple JSON précédent :

Configurer plusieurs clients de service avec des noms différents

Supposons que vous disposez de deux comptes de stockage : un pour les informations privées et un autre pour les informations publiques. Votre application transfère des données du compte de stockage public vers le privé après une opération. Vous devez avoir deux clients de service de stockage. Pour différencier ces deux clients, utilisez la méthode d’extension WithName :

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

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

En utilisant un contrôleur ASP.NET Core comme exemple, accédez au client de service nommé à l’aide de l’interface 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");
    }
}

Le client de service sans nom est toujours disponible, de la même manière qu’auparavant. Les clients nommés sont additifs.

Configurer une nouvelle stratégie de nouvelles tentatives

À un moment donné, vous pouvez modifier les paramètres par défaut d’un client de service. Par exemple, vous pouvez souhaiter des paramètres de nouvelles tentatives différents ou utiliser une autre version de l’API de service. Vous pouvez définir les paramètres de nouvelles tentatives globalement ou par service. Supposons que vous disposez du fichier appsettings.json suivant dans votre projet 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"
  }
}

Vous pouvez modifier la stratégie de nouvelles tentatives en fonction de vos besoins, comme suit :

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

Vous pouvez également placer des remplacements de stratégie de nouvelles tentatives dans le fichier appsettings.json :

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

Voir aussi