Azure SDK for .NET 的相依性插入

本文示範如何從最新的適用於 .NET 的最新 Azure 用戶端連結庫註冊 Azure 服務用戶端,以在 .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 祕密、Blob 儲存體和服務匯流排程式庫。 安裝下列套件以遵循:

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 儲存體和服務匯流排用戶端會分別使用 AddSecretClientAddBlobServiceClientAddServiceBusClientWithNamespace 註冊。 會傳遞 Uristring 型別引數。 若要避免明確指定這些 URL,請參閱將組態與程式碼分開儲存一節。
  • DefaultAzureCredential 可用來滿足各個已註冊用戶端的 TokenCredential 引數需求。 建立其中一個用戶端時,會使用 DefaultAzureCredential 進行驗證。
  • 服務匯流排子用戶端會使用子用戶端和對應的選項類型,為服務上的每個佇列註冊。 子用戶端的佇列名稱是使用服務註冊以外的個別方法擷取,因為 GetQueuesAsync 方法必須以異步方式執行。

使用所註冊的用戶端

註冊用戶端時,如註冊用戶端和子用戶端一節所述,您現在可以使用這些用戶端。 在下列範例中,建構函式插入會用於取得 ASP.NET Core API 控制器中的 Blob 儲存體用戶端和服務匯流排傳送者子用戶端的中心:

[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.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 檔案。 您可以使用 IConfiguration 擷取 JSON 組態檔中的設定。

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

另請參閱