.NET용 Azure SDK를 통해 종속성 주입

이 문서에서는 .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.BuilderMicrosoft.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 클라이언트는 각각 AddSecretClient, AddBlobServiceClientAddServiceBusClientWithNamespace를 사용하여 등록됩니다. Uristring 형식화된 인수가 전달됩니다. 이러한 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 파일이 있을 수 있습니다. 다른 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 샘플에서:

서로 다른 이름을 사용하여 여러 서비스 클라이언트 구성

두 개의 스토리지 계정이 있다고 상상해 보세요. 하나는 개인 정보용이고 다른 하나는 공개 정보용입니다. 특정 작업 후 앱이 퍼블릭 스토리지 계정의 데이터를 프라이빗 스토리지 계정으로 전송합니다. 스토리지 서비스 클라이언트가 두 개 필요합니다. 이러한 두 클라이언트를 구분하려면 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
    }
  }
}

참고 항목