Поделиться через


Внедрение зависимостей с помощью пакета Azure SDK для .NET

В этой статье показано, как зарегистрировать клиенты службы Azure из последних клиентских библиотек Azure для .NET для внедрения зависимостей в приложении .NET. Каждое современное приложение .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 Secret, BLOB-объектов, служебная шина и Azure OpenAI. Установите следующие пакеты, чтобы выполнить следующие действия:

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

Регистрация клиентов и подклиентов

Клиент службы — это точка входа в API для службы Azure— из нее пользователи библиотеки могут вызывать все операции, которые предоставляет служба и легко реализовать наиболее распространенные сценарии. Где это упрощает проектирование 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;
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;
}

В предыдущем коде:

  • Секреты Key Vault, хранилище BLOB-объектов и служебная шина клиенты регистрируются с помощью AddSecretClientAddBlobServiceClient и AddServiceBusClientWithNamespaceсоответственно. Передаются Uriаргументы - и stringтипизированные. Чтобы избежать явного указания этих URL-адресов, ознакомьтесь с конфигурацией Магазина отдельно от раздела кода .
  • DefaultAzureCredential используется для удовлетворения требования аргумента TokenCredential для каждого зарегистрированного клиента. При создании DefaultAzureCredential одного из клиентов используется для проверки подлинности.
  • служебная шина подклиенты регистрируются для каждой очереди в службе с помощью подклиента и соответствующих типов параметров. Имена очередей для подклиентов извлекаются с помощью отдельного метода вне регистрации службы, так как GetQueuesAsync метод должен выполняться асинхронно.
  • Клиент Azure OpenAI регистрируется с помощью настраиваемой фабрики клиентов с помощью AddClient метода, который обеспечивает контроль над созданием экземпляра клиента. Пользовательские клиентские фабрики полезны в следующих случаях:
    • Во время построения клиента необходимо использовать другие зависимости.
    • Метод расширения регистрации не существует для клиента службы, который требуется зарегистрировать.

Использование зарегистрированных клиентов

Зарегистрированные клиенты, как описано в разделе "Регистрация клиентов и подклиентов ", теперь можно использовать их. В следующем примере внедрение конструктора используется для получения клиента хранилища BLOB-объектов и фабрики для подклиентов отправителя служебная шина в контроллере API ядра ASP.NET:

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

Хранение конфигурации отдельно от кода

В разделе "Регистрация клиентов и подклиентов" вы явно передали Uriтипизированные переменные конструкторам клиента. Такой подход может вызвать проблемы при выполнении кода в различных средах при разработке и в работе. Команда разработчиков .NET предлагает хранить такие конфигурации в отдельных JSON-файлах для соответствующих сред. Например, в файле appsettings.Development.js можно хранить параметры среды разработки. В другом файле, appsettings.Production.js, храните параметры рабочей среды и т. д. У файлов должен быть следующий формат.

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

В JSON-файл можно добавить любые свойства из ClientOptions класса. Параметры в файле конфигурации 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
    }
  }
}

См. также