

第 4 版 (V4) 適用於 .NET 的 AWS SDK 已發行！

如需有關中斷變更和遷移應用程式的資訊，請參閱[遷移主題](https://docs.aws.amazon.com/sdk-for-net/v4/developer-guide/net-dg-v4.html)。

 [https://docs.aws.amazon.com/sdk-for-net/v4/developer-guide/net-dg-v4.html](https://docs.aws.amazon.com/sdk-for-net/v4/developer-guide/net-dg-v4.html)

本文為英文版的機器翻譯版本，如內容有任何歧義或不一致之處，概以英文版為準。

# 使用 適用於 .NET 的 AWS SDK
<a name="net-dg-sdk-features"></a>

本節提供有關建立應用程式時 適用於 .NET 的 AWS SDK 可能需要考慮的 功能的資訊。

開始之前，請確定您已[設定環境](net-dg-config.md)並[設定專案](configuring-the-sdk.md)。

如需針對特定 AWS 服務開發軟體以及程式碼範例的資訊，請參閱 [呼叫 AWS 服務](working-with-aws-services.md)。如需其他程式碼範例，請參閱 [適用於 .NET 的 SDK (v4) 程式碼範例](csharp_code_examples.md)。

**Topics**
+ [非同步程式設計](sdk-net-async-api.md)
+ [分頁](paginators.md)
+ [支援 HTTP 2](http2-support.md)
+ [其他工具](sdk-features-additional-tools.md)

# 使用 以非同步方式進行程式設計 適用於 .NET 的 AWS SDK
<a name="sdk-net-async-api"></a>

 適用於 .NET 的 AWS SDK 使用*任務型非同步模式 (TAP)* 進行非同步實作。若要進一步了解 TAP，請參閱 https：//docs.microsoft.com 上的[任務型非同步模式 (TAP)](https://learn.microsoft.com/en-us/dotnet/standard/asynchronous-programming-patterns/task-based-asynchronous-pattern-tap)。

本主題概述如何在呼叫 AWS 服務用戶端時使用 TAP。

 適用於 .NET 的 AWS SDK API 中的非同步方法是根據 `Task`類別或 `Task<TResult>`類別的操作。如需這些類別的相關資訊，請參閱 docs.microsoft.com：//[https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.task](https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.task)[TResult](https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.task-1)。

當您的程式碼中呼叫這些 API 方法時，它們必須在使用 `async`關鍵字宣告的函數內呼叫，如下列範例所示。

```
static async Task Main(string[] args)
{
  ...
  // Call the function that contains the asynchronous API method.
  // Could also call the asynchronous API method directly from Main
  //  because Main is declared async
  var response = await ListBucketsAsync();
  Console.WriteLine($"Number of buckets: {response.Buckets.Count}");
  ...
}

// Async method to get a list of Amazon S3 buckets.
private static async Task<ListBucketsResponse> ListBucketsAsync()
{
  ...
  var response = await s3Client.ListBucketsAsync();
  return response;
}
```

如上述程式碼片段所示，`async`宣告的偏好範圍是 `Main`函數。設定此`async`範圍可確保對 AWS 服務用戶端的所有呼叫都必須是非同步的。如果您因為某些原因而無法宣告`Main`為非同步，您可以在 以外的函數上使用 `async`關鍵字，`Main`然後從該處呼叫 API 方法，如下列範例所示。

```
static void Main(string[] args)
{
  ...
  Task<ListBucketsResponse> response = ListBucketsAsync();
  Console.WriteLine($"Number of buckets: {response.Result.Buckets.Count}");
  ...
}

// Async method to get a list of Amazon S3 buckets.
private static async Task<ListBucketsResponse> ListBucketsAsync()
{
  ...
  var response = await s3Client.ListBucketsAsync();
  return response;
}
```

請注意，當您使用此模式`Main`時， 中需要的特殊`Task<>`語法。此外，您必須使用回應**`Result`**的成員來取得資料。

您可以在 [建立簡單的應用程式](quick-start.md)區段 ([簡單的跨平台應用程式](quick-start-s3-1-cross.md) 和 [簡單的 Windows 型應用程式](quick-start-s3-1-winvs.md)) 和 中查看非同步呼叫 AWS 服務用戶端的完整範例[引導式程式碼範例高階程式庫和架構](tutorials-examples.md)。

# 在 中使用分頁結果 適用於 .NET 的 AWS SDK
<a name="paginators"></a>

有些 AWS 服務會收集和存放大量資料，您可以使用 的 API 呼叫來擷取這些資料 適用於 .NET 的 AWS SDK。如果您想要擷取的資料量對於單一 API 呼叫變得太大，您可以透過使用*分頁*將結果分成更易於管理的部分。

為了讓您能夠執行分頁，軟體開發套件中許多服務用戶端的請求和回應物件會提供*接續字符* （通常名為 `NextToken`)。其中一些服務用戶端也提供**分頁程式**。

分頁程式可讓您避免接續字符的額外負荷，這可能涉及迴圈、狀態變數、多個 API 呼叫等。當您使用分頁程式時，您可以透過迴圈`foreach`的宣告單行程式碼，從 AWS 服務擷取資料。如果需要多個 API 呼叫來擷取資料，分頁器會為您處理。

## 在哪裡可以找到分頁程式？
<a name="paginators-find-them"></a>

並非所有 服務都提供分頁程式。判斷服務是否為特定 API 提供分頁器的一種方法是查看 [適用於 .NET 的 AWS SDK API 參考](https://docs.aws.amazon.com/sdkfornet/v4/apidocs/)中服務用戶端類別的定義。

例如，如果您檢查 [AmazonCloudWatchLogsClient](https://docs.aws.amazon.com/sdkfornet/v4/apidocs/items/CloudWatchLogs/TCloudWatchLogsClient.html) 類別的定義，您會看到 `Paginators` 屬性。這是為 Amazon CloudWatch Logs 提供分頁器的 屬性。

## 分頁程式提供什麼？
<a name="paginators-use-them"></a>

分頁程式包含可讓您查看完整回應的屬性。它們通常也包含一或多個屬性，可讓您存取最有趣的回應部分，我們將呼叫*關鍵結果*。

例如，在先前`AmazonCloudWatchLogsClient`提到的 中， `Paginator` 物件包含具有 API 呼叫中完整 [DescribeLogGroupsResponse](https://docs.aws.amazon.com/sdkfornet/v4/apidocs/items/CloudWatchLogs/TDescribeLogGroupsResponse.html) 物件的 `Responses` 屬性。此`Responses`屬性包含日誌群組的集合。

Paginator 物件也包含一個名為 的金鑰結果`LogGroups`。此屬性只會保留回應的日誌群組部分。擁有此金鑰結果可讓您在許多情況下減少和簡化程式碼。

## 同步與非同步分頁
<a name="paginators-sync-async"></a>

分頁程式提供同步和非同步的分頁機制。同步分頁可在 .NET Framework 4.7.2 （或更新版本） 專案中使用。.NET Core 專案 (.NET Core 3.1、.NET 5 等） 提供非同步分頁。

由於建議使用非同步操作和 .NET Core，接下來的範例會顯示非同步分頁。有關如何使用同步分頁和 .NET Framework 4.7.2 （或更新版本） 執行相同任務的資訊會顯示在 中的範例之後。 [分頁程式的其他考量事項](#paginators-additional)

## 範例
<a name="paginators-example"></a>

下列範例說明如何使用 適用於 .NET 的 AWS SDK 來顯示日誌群組的清單。反之，此範例示範如何使用和不使用分頁程式來執行此操作。在查看稍後顯示的完整程式碼之前，請考慮下列程式碼片段。

**在沒有分頁器的情況下取得 CloudWatch 日誌群組**

```
      // Loop as many times as needed to get all the log groups
      var request = new DescribeLogGroupsRequest{Limit = LogGroupLimit};
      do
      {
        Console.WriteLine($"Getting up to {LogGroupLimit} log groups...");
        var response = await cwClient.DescribeLogGroupsAsync(request);
        foreach(var logGroup in response.LogGroups)
        {
          Console.WriteLine($"{logGroup.LogGroupName}");
        }
        request.NextToken = response.NextToken;
      } while(!string.IsNullOrEmpty(request.NextToken));
```

**使用分頁器取得 CloudWatch 日誌群組**

```
      // No need to loop to get all the log groups--the SDK does it for us behind the scenes
      var paginatorForLogGroups =
        cwClient.Paginators.DescribeLogGroups(new DescribeLogGroupsRequest());
      await foreach(var logGroup in paginatorForLogGroups.LogGroups)
      {
        Console.WriteLine(logGroup.LogGroupName);
      }
```

這兩個程式碼片段的結果完全相同，因此使用分頁器的優勢可以清楚地看到。

**注意**  
在您嘗試建置並執行完整程式碼之前，請確定您已[設定環境和專案](net-dg-config.md)。  
您可能還需要 [Microsoft.Bcl.AsyncInterfaces](https://www.nuget.org/packages/Microsoft.Bcl.AsyncInterfaces/) NuGet 套件，因為非同步分頁程式使用 `IAsyncEnumerable` 介面。

### 完成程式碼
<a name="paginators-complete-code"></a>

本節顯示此範例的相關參考和完整程式碼。

#### 開發套件參考
<a name="w2aac13c13c23c19b5b1"></a>

NuGet 套件：
+ [AWSSDK.CloudWatch](https://www.nuget.org/packages/AWSSDK.CloudWatch)

程式設計元素：
+ 命名空間 [Amazon.CloudWatch](https://docs.aws.amazon.com/sdkfornet/v4/apidocs/items/CloudWatch/NCloudWatch.html)

  [AmazonCloudWatchLogsClient](https://docs.aws.amazon.com/sdkfornet/v4/apidocs/items/CloudWatchLogs/TCloudWatchLogsClient.html) 類別
+ 命名空間 [Amazon.CloudWatchLogs.Model](https://docs.aws.amazon.com/sdkfornet/v4/apidocs/items/CloudWatchLogs/NCloudWatchLogsModel.html)

  類別 [DescribeLogGroupsRequest](https://docs.aws.amazon.com/sdkfornet/v4/apidocs/items/CloudWatchLogs/TDescribeLogGroupsRequest.html)

  類別 [DescribeLogGroupsResponse](https://docs.aws.amazon.com/sdkfornet/v4/apidocs/items/CloudWatchLogs/TDescribeLogGroupsResponse.html)

  類別 [LogGroup](https://docs.aws.amazon.com/sdkfornet/v4/apidocs/items/CloudWatchLogs/TLogGroup.html)

#### 完整程式碼
<a name="w2aac13c13c23c19b7b1"></a>

```
using System;
using System.Threading.Tasks;
using Amazon.CloudWatchLogs;
using Amazon.CloudWatchLogs.Model;

namespace CWGetLogGroups
{
  class Program
  {
    // A small limit for demonstration purposes
    private const int LogGroupLimit = 3;

    //
    // Main method
    static async Task Main(string[] args)
    {
      var cwClient = new AmazonCloudWatchLogsClient();
      await DisplayLogGroupsWithoutPaginators(cwClient);
      await DisplayLogGroupsWithPaginators(cwClient);
    }


    //
    // Method to get CloudWatch log groups without paginators
    private static async Task DisplayLogGroupsWithoutPaginators(IAmazonCloudWatchLogs cwClient)
    {
      Console.WriteLine("\nGetting list of CloudWatch log groups without using paginators...");
      Console.WriteLine("------------------------------------------------------------------");

      // Loop as many times as needed to get all the log groups
      var request = new DescribeLogGroupsRequest{Limit = LogGroupLimit};
      do
      {
        Console.WriteLine($"Getting up to {LogGroupLimit} log groups...");
        DescribeLogGroupsResponse response = await cwClient.DescribeLogGroupsAsync(request);
        foreach(LogGroup logGroup in response.LogGroups)
        {
          Console.WriteLine($"{logGroup.LogGroupName}");
        }
        request.NextToken = response.NextToken;
      } while(!string.IsNullOrEmpty(request.NextToken));
    }


    //
    // Method to get CloudWatch log groups by using paginators
    private static async Task DisplayLogGroupsWithPaginators(IAmazonCloudWatchLogs cwClient)
    {
      Console.WriteLine("\nGetting list of CloudWatch log groups by using paginators...");
      Console.WriteLine("-------------------------------------------------------------");

      // Access the key results; i.e., the log groups
      // No need to loop to get all the log groups--the SDK does it for us behind the scenes
      Console.WriteLine("\nFrom the key results...");
      Console.WriteLine("------------------------");
      IDescribeLogGroupsPaginator paginatorForLogGroups =
        cwClient.Paginators.DescribeLogGroups(new DescribeLogGroupsRequest());
      await foreach(LogGroup logGroup in paginatorForLogGroups.LogGroups)
      {
        Console.WriteLine(logGroup.LogGroupName);
      }

      // Access the full response
      // Create a new paginator, do NOT reuse the one from above
      Console.WriteLine("\nFrom the full response...");
      Console.WriteLine("--------------------------");
      IDescribeLogGroupsPaginator paginatorForResponses =
        cwClient.Paginators.DescribeLogGroups(new DescribeLogGroupsRequest());
      await foreach(DescribeLogGroupsResponse response in paginatorForResponses.Responses)
      {
        Console.WriteLine($"Content length: {response.ContentLength}");
        Console.WriteLine($"HTTP result: {response.HttpStatusCode}");
        Console.WriteLine($"Metadata: {response.ResponseMetadata}");
        Console.WriteLine("Log groups:");
        foreach(LogGroup logGroup in response.LogGroups) 
        {
          Console.WriteLine($"\t{logGroup.LogGroupName}");
        }
      }
    }
  }
}
```

## 分頁程式的其他考量事項
<a name="paginators-additional"></a>
+ **分頁程式無法多次使用**

  如果您需要程式碼中多個位置的特定 AWS 分頁器結果，則不得多次使用分頁器物件。反之，請在每次需要時建立新的分頁器。此概念顯示在 `DisplayLogGroupsWithPaginators`方法中的上述範例程式碼中。
+ **同步分頁**

  同步分頁適用於 .NET Framework 4.7.2 （或更新版本） 專案。

  若要查看，請建立 .NET Framework 4.7.2 （或更新版本） 專案，並將上述程式碼複製到其中。然後，只需從兩個`foreach`分頁器呼叫中移除`await`關鍵字，如下列範例所示。

  ```
  /*await*/ foreach(var logGroup in paginatorForLogGroups.LogGroups)
  {
    Console.WriteLine(logGroup.LogGroupName);
  }
  ```

  建置並執行專案，以查看與非同步分頁相同的結果。

# 在 中支援 HTTP 2 適用於 .NET 的 AWS SDK
<a name="http2-support"></a>

有些 AWS 服務和操作需要 HTTP 2。例如，Amazon Transcribe Streaming 中的雙向串流無法透過 HTTP 1.1 進行，因此需要 HTTP 2。 適用於 .NET 的 AWS SDK 新增對 HTTP 2 的 第 4 版支援，讓您可以在應用程式中使用這些操作。對於雙向 HTTP 2 操作，接收串流時 SDK 的行為類似於 HTTP 1.1 的行為。也就是說，當使用 SDK 的應用程式將事件傳送到服務時，請求會有開發人員指派的發佈者。

若要查看此行為的實際運作狀態，請考慮下列 Amazon Transcribe Streaming 的範例。它使用 [Amazon.TranscribeStreaming](https://docs.aws.amazon.com/sdkfornet/v4/apidocs/items/TranscribeStreaming/NTranscribeStreaming.html) 和 [Amazon.TranscribeStreaming.Model](https://docs.aws.amazon.com/sdkfornet/v4/apidocs/items/TranscribeStreaming/NTranscribeStreamingModel.html) 命名空間。

在此範例中，開發人員使用回呼函數定義 `StartStreamTranscriptionRequest.AudioStreamPublisher` 屬性，即 .NET `Func`。開發套件使用 `Func` 定義的 `AudioStreamPublisher` ，從使用者的程式碼提取事件以串流至使用者。軟體開發套件會呼叫 ，`Func`直到傳回 null。

此程式碼示範如何將檔案的音訊串流至 Amazon Transcribe Streaming 進行處理。

```
using Amazon;
using Amazon.TranscribeStreaming;
using Amazon.TranscribeStreaming.Model;

CancellationTokenSource cancelSource = new CancellationTokenSource();

var client = new AmazonTranscribeStreamingClient(RegionEndpoint.USEast1);

var startRequest = new StartStreamTranscriptionRequest
{
    LanguageCode = LanguageCode.EnUS,
    MediaEncoding = MediaEncoding.Flac,
    MediaSampleRateHertz = 44100,
    NumberOfChannels = 2,
    EnableChannelIdentification = true
};

Stream fileStream = File.OpenRead("hello-world.flac");
var buffer = new byte[1024 * 10];
startRequest.AudioStreamPublisher += async () =>
{
    var bytesRead = await fileStream.ReadAsync(buffer, 0, buffer.Length);

    if (bytesRead == 0)
        return null;

    var audioEvent = new AudioEvent
    {
        AudioChunk = new MemoryStream(buffer, 0, bytesRead)
    };

    return audioEvent;
};

using var response = await client.StartStreamTranscriptionAsync(startRequest);
Console.WriteLine(response.HttpStatusCode);

response.TranscriptResultStream.ExceptionReceived += TranscriptResultStream_ExceptionReceived;
response.TranscriptResultStream.TranscriptEventReceived += TranscriptResultStream_TranscriptEventReceived;

void TranscriptResultStream_ExceptionReceived(object? sender, Amazon.Runtime.EventStreams.EventStreamExceptionReceivedArgs<TranscribeStreamingEventStreamException> e)
{
    Console.WriteLine(e.EventStreamException.Message);
    cancelSource.Cancel();
}
void TranscriptResultStream_TranscriptEventReceived(object? sender, Amazon.Runtime.EventStreams.EventStreamEventReceivedArgs<TranscriptEvent> e)
{
    foreach (var result in e.EventStreamEvent.Transcript.Results)
    {
        if (!string.Equals("ch_0", result.ChannelId, StringComparison.OrdinalIgnoreCase))
            continue;

        var text = result.Alternatives[0].Transcript;
        if (!string.IsNullOrEmpty(text))
        {
            Console.WriteLine(text);
        }
    }
}

_ = response.TranscriptResultStream.StartProcessingAsync();

try
{
    await Task.Delay(10000, cancelSource.Token);
}
catch (TaskCanceledException) { }
```

**警告**  
有些雙向 HTTP 2 操作，例如來自 Amazon Bedrock 的 `InvokeModelWithBidirectionalStreamAsync`方法，即 [Amazon.BedrockRuntime](https://docs.aws.amazon.com/sdkfornet/v4/apidocs/items/BedrockRuntime/NBedrockRuntime.html) 命名空間，在發佈某些事件之前，不會傳回來自服務用戶端上初始調用的回應。此行為可能會導致您的應用程式遭到封鎖。若要避免這種情況，請區隔向發佈者提供事件的應用程式程式碼，並在不同於在服務用戶端上叫用操作的執行緒上執行。

## 其他考量
<a name="http2-support-additional"></a>
+ 適用於 .NET 的 AWS SDK HTTP 2 的支援僅適用於以 .NET 8 及更高版本為目標的版本。它不適用於以 .NET Framework 為目標的版本。
+ 如需詳細資訊，請參閱 [aws-sdk-net](https://github.com/aws/aws-sdk-net) GitHub 儲存庫中的 [PR 3730](https://github.com/aws/aws-sdk-net/pull/3730)。

# 其他工具
<a name="sdk-features-additional-tools"></a>

以下是一些額外的工具，您可以用來簡化開發、部署和維護 .NET 應用程式的工作。

## AWS 部署工具
<a name="sdk-features-deployment-tool"></a>

在開發機器上開發雲端原生 .NET Core 應用程式之後，您可以使用適用於 .NET CLI 的 AWS 部署工具，更輕鬆地將應用程式部署到 AWS。

如需詳細資訊，請參閱[將應用程式部署到 AWS](deploying.md)。

## AWS 適用於 .NET 的訊息處理架構
<a name="sdk-features-msg-proc"></a>

如果您使用的是 Amazon SQS、Amazon SNS 或 Amazon EventBridge 等服務，您可以利用適用於 .NET AWS 的訊息處理架構。如需詳細資訊，請參閱[AWS 適用於 .NET 的訊息處理架構](msg-proc-fw.md)。

## 與 .NET Acover 整合
<a name="sdk-features-aspire-integrations"></a>

您可以利用與 .NET Aspire 整合的優勢來改善內部開發迴圈。如需詳細資訊，請參閱[在 中 AWS 與 .NET ACache 整合 適用於 .NET 的 AWS SDK](aspire-integrations.md)。