Azure SDK for .NET での依存関係の挿入

この記事では、.NET アプリでの依存関係の挿入のために、最新の .NET 向け Azure クライアント ライブラリから Azure サービス クライアントを登録する方法を示します。 すべての最新の .NET アプリは、Program.cs ファイルで指定されている指示に従って起動します。

パッケージのインストール

Azure.プレフィックス付きパッケージからサービス クライアントを登録して構成するには、以下の操作を行います。

  1. 以下のプロジェクトに Microsoft.Extensions.Azure パッケージをインストールします。

    dotnet add package Microsoft.Extensions.Azure
    
  2. Azure.Identity パッケージをインストールして、このような型を受け入れるすべての登録済みクライアントの認証に使用する TokenCredential 型を構成します。

    dotnet add package Azure.Identity
    

デモンストレーションのために、この記事のサンプル コードでは Key Vault シークレット、Blob Storage、Service Bus ライブラリを使用します。 次のパッケージをインストールして、以下の手順に従ってください。

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

クライアントとサブクライアントを登録する

サービス クライアントは、Azure サービスの API へのエントリ ポイントです。ライブラリ ユーザーは、サービスが提供するすべての操作を呼び出すことができ、最も一般的なシナリオを簡単に実装できます。 API の設計が簡素化され、サービス呼び出しのグループは、より小さなサブクライアント型を中心に編成できます。 たとえば、ServiceBusClient はメッセージを発行するために ServiceBusSender のサブクライアントを、またはメッセージを使用するために ServiceBusReceiver のサブクライアントを追加登録できます。

Program.cs ファイルで、AddAzureClients 拡張メソッドを呼び出して、各サービスのクライアントを登録します。 次のコード サンプルには、Microsoft.AspNetCore.Builder 名前空間と 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;
}

上のコードでは以下の操作が行われます。

  • Key Vault シークレット、Blob Storage、Service Bus クライアントは、それぞれ AddSecretClientAddBlobServiceClientAddServiceBusClientWithNamespace を使用して登録されます。 Uri 型、string 型の引数が渡されます。 URL を明示的に指定しないようにするには、「コードとは別に構成を格納する」のセクションを参照してください。
  • DefaultAzureCredential は、登録されている各クライアントの TokenCredential 引数要件を満たすために使用されます。 いずれかのクライアントが作成されると、DefaultAzureCredential が認証に使用されます。
  • Service Bus サブクライアントは、サブクライアントと対応するオプションの種類を使用して、サービス上の各キューに登録されます。 サブクライアントのキュー名は、サービス登録とは別のメソッドを使用して取得されます。これは、GetQueuesAsync メソッドを非同期的に実行する必要があるためです。

登録済みクライアントを使用する

クライアントとサブクライアントの登録」セクションの説明に従ってクライアントを登録した後に、それらを使用できます。 次の例では、コンストラクターの挿入を使用して、ASP.NET Core API コントローラーで Blob Storage クライアントを取得します。

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

コードとは別に構成を格納する

クライアントとサブクライアントの登録」セクションでは、Uri に型指定された変数をクライアント コンストラクターに明示的に渡しました。 このアプローチにより、開発および運用中に異なる環境に対してコードを実行するときに問題が発生するおそれがあります。 .NET チームは、このような構成を環境に依存する JSON ファイルに格納するように提案しています。 たとえば、appsettings.Development.json ファイルに開発環境の設定を含めることができます。 もう 1 つの appsettings.Production.json には、運用環境の設定などが含まれます。 ファイル形式は次のとおりです。

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

ClientOptions クラスから JSON ファイルに任意のプロパティを追加できます。 JSON 構成ファイルの設定は、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"));
});

上記の JSON の例では、次のように指定されています。

異なる名前で複数のサービス クライアントを構成する

2 つのストレージ アカウントがあるとします。1 つは個人情報用で、もう 1 つは公開情報用です。 アプリでは、何らかの操作後に、パブリックからプライベート ストレージ アカウントにデータが転送されます。 2 つのストレージ サービス クライアントが必要です。 これら 2 つのクライアントを区別するには、WithName 拡張メソッドを使用します。

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

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

例として ASP.NET Core コントローラーを使用して、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");
    }
}

名前のないサービス クライアントは、前と同じ方法で引き続き使用できます。 名前付きクライアントは付加的なものです。

新しい再試行ポリシーを構成する

ある時点で、サービス クライアントの既定の設定の変更が必要になる場合があります。 たとえば、さまざまな再試行設定が必要な場合や、別のサービス API バージョンを使用する場合です。 再試行の設定はグローバルに、またはサービスごとに行うことができます。 ASP.NET Core プロジェクトに次の 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"
  }
}

再試行ポリシーは、必要に応じて以下のように変更できます。

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

また、appsettings.json ファイルに再試行ポリシーのオーバーライドを配置することもできます。

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

関連項目