

 適用於 .NET 的 AWS SDK V3 已進入維護模式。

我們建議您遷移至 [適用於 .NET 的 AWS SDK V4](https://docs.aws.amazon.com/sdk-for-net/v4/developer-guide/welcome.html)。如需如何遷移的其他詳細資訊和資訊，請參閱我們的[維護模式公告](https://aws.amazon.com/blogs/developer/aws-sdk-for-net-v3-maintenance-mode-announcement/)。

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

# 在 中使用 AWS 服務 適用於 .NET 的 AWS SDK
<a name="working-with-aws-services"></a>

下列各節包含範例、教學課程、任務和指南，說明如何使用 適用於 .NET 的 AWS SDK 來使用 AWS 服務。這些範例和教學課程依賴 適用於 .NET 的 AWS SDK 提供的 API。若要查看 API 中有哪些類別和方法可用，請參閱 [適用於 .NET 的 AWS SDK API 參考](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/)。

如果您是初次使用 適用於 .NET 的 AWS SDK，建議您先查看[快速導覽](quick-start.md)主題。它為您提供 SDK 的簡介。

您可以在 GitHub 的程式碼範例[AWS 儲存庫和 awslabs 儲存庫中找到更多程式碼範例](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/dotnetv3)。 [https://github.com/awslabs/aws-sdk-net-samples](https://github.com/awslabs/aws-sdk-net-samples)

開始之前，請確定您已[設定環境和專案](net-dg-config.md)。也請檢閱 中的資訊[開發套件功能](net-dg-sdk-features.md)。

**Topics**
+ [含指引的程式碼範例](tutorials-examples.md)
+ [AWS Lambda](aws-lambda.md)
+ [高階程式庫和架構](high-level-libraries.md)
+ [其他服務和組態](other-apis-intro.md)

# 具有 指引的程式碼範例 適用於 .NET 的 AWS SDK
<a name="tutorials-examples"></a>

下列各節包含程式碼範例，並提供範例的指引。他們可以協助您了解如何使用 適用於 .NET 的 AWS SDK 來使用 AWS 服務。

如果您是初次使用 適用於 .NET 的 AWS SDK，建議您先查看[快速導覽](quick-start.md)主題。它為您提供 SDK 的簡介。

開始之前，請確定您已[設定環境和專案](net-dg-config.md)。也請檢閱 中的資訊[開發套件功能](net-dg-sdk-features.md)。

**Topics**
+ [CloudFormation](cloudformation-apis-intro.md)
+ [Amazon Cognito](cognito-apis-intro.md)
+ [DynamoDB](dynamodb-intro.md)
+ [Amazon EC2](ec2-apis-intro.md)
+ [IAM](iam-apis-intro.md)
+ [Amazon S3](s3-apis-intro.md)
+ [Amazon SNS](sns-apis-intro.md)
+ [Amazon SQS](sqs-apis-intro.md)

# CloudFormation 使用 存取 適用於 .NET 的 AWS SDK
<a name="cloudformation-apis-intro"></a>

 適用於 .NET 的 AWS SDK 支援 [AWS CloudFormation](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/)，可預測並重複建立和佈建 AWS 基礎設施部署。

## API
<a name="w2aac19c15c11b5"></a>

為 CloudFormation 用戶端 適用於 .NET 的 AWS SDK 提供 APIs。APIs 可讓您使用 範本和堆疊等 CloudFormation 功能。本節包含一些範例，顯示您在使用這些 APIs 時可遵循的模式。若要檢視完整的 APIs 集，請參閱 [適用於 .NET 的 AWS SDK API 參考](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/) （並捲動至「Amazon.CloudFormation」)。

 AWS CloudFormation APIs 由 [AWSSDK.CloudFormation ](https://www.nuget.org/packages/AWSSDK.CloudFormation/)套件提供。

## 先決條件
<a name="w2aac19c15c11b7"></a>

開始之前，請確定您已[設定環境和專案](net-dg-config.md)。也請檢閱 中的資訊[開發套件功能](net-dg-sdk-features.md)。

## 主題
<a name="w2aac19c15c11b9"></a>

**Topics**
+ [

## API
](#w2aac19c15c11b5)
+ [

## 先決條件
](#w2aac19c15c11b7)
+ [

## 主題
](#w2aac19c15c11b9)
+ [列出 AWS 資源](cfn-list-resources.md)

# 使用 列出 AWS 資源 AWS CloudFormation
<a name="cfn-list-resources"></a>

此範例說明如何使用 適用於 .NET 的 AWS SDK 列出 CloudFormation 堆疊中的資源。此範例使用低階 API。應用程式不需要任何引數，但只會收集使用者登入資料可存取的所有堆疊資訊，然後顯示這些堆疊的相關資訊。

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

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

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

  [AmazonCloudFormationClient](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/CloudFormation/TCloudFormationClient.html) 類別
+ 命名空間 [Amazon.CloudFormation.Model](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/CloudFormation/NCloudFormationModel.html)

  類別 [ICloudFormationPaginatorFactory.DescribeStacks](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/CloudFormation/MICloudFormationPaginatorFactoryDescribeStacksDescribeStacksRequest.html)

  類別 [DescribeStackResourcesRequest](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/CloudFormation/TDescribeStackResourcesRequest.html)

  類別 [DescribeStackResourcesResponse](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/CloudFormation/TDescribeStackResourcesResponse.html)

  類別[堆疊](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/CloudFormation/TStack.html)

  類別 [StackResource](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/CloudFormation/TStackResource.html)

  類別[標籤](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/CloudFormation/TTag.html)

```
using Amazon.CloudFormation;
using Amazon.CloudFormation.Model;
using Amazon.Runtime;

namespace CloudFormationActions;

public static class HelloCloudFormation
{
    public static IAmazonCloudFormation _amazonCloudFormation;

    static async Task Main(string[] args)
    {
        // Create the CloudFormation client
        _amazonCloudFormation = new AmazonCloudFormationClient();
        Console.WriteLine($"\nIn Region: {_amazonCloudFormation.Config.RegionEndpoint}");

        // List the resources for each stack
        await ListResources();
    }

    /// <summary>
    /// Method to list stack resources and other information.
    /// </summary>
    /// <returns>True if successful.</returns>
    public static async Task<bool> ListResources()
    {
        try
        {
            Console.WriteLine("Getting CloudFormation stack information...");

            // Get all stacks using the stack paginator.
            var paginatorForDescribeStacks =
                _amazonCloudFormation.Paginators.DescribeStacks(
                    new DescribeStacksRequest());
            await foreach (Stack stack in paginatorForDescribeStacks.Stacks)
            {
                // Basic information for each stack
                Console.WriteLine("\n------------------------------------------------");
                Console.WriteLine($"\nStack: {stack.StackName}");
                Console.WriteLine($"  Status: {stack.StackStatus.Value}");
                Console.WriteLine($"  Created: {stack.CreationTime}");

                // The tags of each stack (etc.)
                if (stack.Tags.Count > 0)
                {
                    Console.WriteLine("  Tags:");
                    foreach (Tag tag in stack.Tags)
                        Console.WriteLine($"    {tag.Key}, {tag.Value}");
                }

                // The resources of each stack
                DescribeStackResourcesResponse responseDescribeResources =
                    await _amazonCloudFormation.DescribeStackResourcesAsync(
                        new DescribeStackResourcesRequest
                        {
                            StackName = stack.StackName
                        });
                if (responseDescribeResources.StackResources.Count > 0)
                {
                    Console.WriteLine("  Resources:");
                    foreach (StackResource resource in responseDescribeResources
                                 .StackResources)
                        Console.WriteLine(
                            $"    {resource.LogicalResourceId}: {resource.ResourceStatus}");
                }
            }

            Console.WriteLine("\n------------------------------------------------");
            return true;
        }
        catch (AmazonCloudFormationException ex)
        {
            Console.WriteLine("Unable to get stack information:\n" + ex.Message);
            return false;
        }
        catch (AmazonServiceException ex)
        {
            if (ex.Message.Contains("Unable to get IAM security credentials"))
            {
                Console.WriteLine(ex.Message);
                Console.WriteLine("If you are usnig SSO, be sure to install" +
                                  " the AWSSDK.SSO and AWSSDK.SSOOIDC packages.");
            }
            else
            {
                Console.WriteLine(ex.Message);
                Console.WriteLine(ex.StackTrace);
            }

            return false;
        }
        catch (ArgumentNullException ex)
        {
            if (ex.Message.Contains("Options property cannot be empty: ClientName"))
            {
                Console.WriteLine(ex.Message);
                Console.WriteLine("If you are using SSO, have you logged in?");
            }
            else
            {
                Console.WriteLine(ex.Message);
                Console.WriteLine(ex.StackTrace);
            }

            return false;
        }
    }
```

# 使用 Amazon Cognito 驗證使用者
<a name="cognito-apis-intro"></a>

**注意**  
本主題中的資訊專屬於以 .NET Framework 和 3.3 適用於 .NET 的 AWS SDK 版及更早版本為基礎的專案。

使用 Amazon Cognito Identity，您可以為使用者建立唯一身分，並對其進行身分驗證，以安全地存取您的 AWS 資源，例如 Amazon S3 或 Amazon DynamoDB。Amazon Cognito Identity 支援公有身分提供者，例如 Amazon、Facebook、Twitter/Digits、Google 或任何 OpenID Connect 相容提供者，以及未驗證的身分。Amazon Cognito 也支援[開發人員驗證的身分](https://aws.amazon.com/blogs/mobile/amazon-cognito-announcing-developer-authenticated-identities/)，可讓您使用自己的後端身分驗證程序註冊和驗證使用者，同時仍使用 Amazon Cognito Sync 同步使用者資料和存取 AWS 資源。

如需 [Amazon Cognito](https://aws.amazon.com/cognito/) 的詳細資訊，請參閱《[Amazon Cognito 開發人員指南](https://docs.aws.amazon.com/cognito/latest/developerguide/)》。

下列程式碼範例示範如何輕鬆使用 Amazon Cognito Identity。此[憑證提供者](cognito-creds-provider.md)範例示範如何建立和驗證使用者身分。此[CognitoAuthentication 延伸程式庫](cognito-authentication-extension.md)範例示範如何使用 CognitoAuthentication 延伸程式庫來驗證 Amazon Cognito 使用者集區。

**Topics**
+ [憑證提供者](cognito-creds-provider.md)
+ [CognitoAuthentication 延伸程式庫](cognito-authentication-extension.md)

# Amazon Cognito 登入資料提供者
<a name="cognito-creds-provider"></a>

**注意**  
本主題中的資訊專屬於以 .NET Framework 和 3.3 適用於 .NET 的 AWS SDK 版及更早版本為基礎的專案。

 `Amazon.CognitoIdentity.CognitoAWSCredentials`位於 [AWSSDK.CognitoIdentity](https://www.nuget.org/packages/AWSSDK.CognitoIdentity/) NuGet 套件中的 是登入資料物件，使用 Amazon Cognito 和 AWS Security Token Service (AWS STS) 擷取登入資料以進行 AWS 呼叫。

設定 `CognitoAWSCredentials` 的第一步是建立「身分集區」。身分集區是您的帳戶專屬的使用者身分資訊存放區。此資訊可跨用戶端平台、裝置和作業系統擷取，因此，如果使用者一開始是在手機上使用您的應用程式，之後再切換到平板電腦，所保存的應用程式資訊仍然可供該使用者使用。您可以從 Amazon Cognito 主控台建立新的身分集區。如果您使用主控台，它還會提供您需要的其他資訊：
+ 您的帳號是 12 位數字的號碼，例如 123456789012，是您帳戶專有。
+ 未驗證角色 ARN - 未驗證的使用者將擔任的角色。例如，此角色可提供您資料的唯讀許可。
+ 已驗證的角色 ARN - 已驗證的使用者將擔任的角色。此角色可提供您資料更多許可。

## 設定 CognitoAWSCredentials
<a name="set-up-cognitoawscredentials"></a>

下列程式碼範例示範如何設定 `CognitoAWSCredentials`，然後您可以使用它以未經驗證的使用者身分呼叫 Amazon S3。這可讓您只使用所需的最少量資料來驗證使用者身分。使用者權限由角色控制，因此您可以依需要設定存取權。

```
CognitoAWSCredentials credentials = new CognitoAWSCredentials(
    accountId,        // Account number
    identityPoolId,   // Identity pool ID
    unAuthRoleArn,    // Role for unauthenticated users
    null,             // Role for authenticated users, not set
    region);
using (var s3Client = new AmazonS3Client(credentials))
{
    s3Client.ListBuckets();
}
```

## 使用 AWS 做為未驗證的使用者
<a name="use-aws-as-an-unauthenticated-user"></a>

下列程式碼範例示範如何以未經驗證的使用者 AWS 身分開始使用 ，然後透過 Facebook 進行身分驗證，並更新登入資料以使用 Facebook 登入資料。使用此方法，您便可已驗證的角色授與不同功能給已驗證身分的使用者。例如您的手機應用程式允許使用者匿名檢視內容，如果使用一或多個設定的提供者身分登入的話，還可讓他們張貼文章。

```
CognitoAWSCredentials credentials = new CognitoAWSCredentials(
    accountId, identityPoolId,
    unAuthRoleArn,    // Role for unauthenticated users
    authRoleArn,      // Role for authenticated users
    region);
using (var s3Client = new AmazonS3Client(credentials))
{
    // Initial use will be unauthenticated
    s3Client.ListBuckets();

    // Authenticate user through Facebook
    string facebookToken = GetFacebookAuthToken();

    // Add Facebook login to credentials. This clears the current AWS credentials
    // and retrieves new AWS credentials using the authenticated role.
    credentials.AddLogin("graph.facebook.com", facebookAccessToken);

    // This call is performed with the authenticated role and credentials
    s3Client.ListBuckets();
}
```

如果您使用 `AmazonCognitoSyncClient` (屬 適用於 .NET 的 AWS SDK的一部分)，`CognitoAWSCredentials` 物件甚至能提供更多功能。如果您同時使用 `AmazonCognitoSyncClient`和 `CognitoAWSCredentials`，則不需要在使用 呼叫 時指定 `IdentityPoolId`和 `IdentityId` 屬性`AmazonCognitoSyncClient`。這些屬性會自動從 `CognitoAWSCredentials` 填入。下一個程式碼範例將對此做說明，並且提供一個事件，只要適用於 `CognitoAWSCredentials` 的 `IdentityId` 有變動時就會通知您。在某些情況下，例如從未驗證使用者變更為已驗證使用者時，`IdentityId` 即可變更。

```
CognitoAWSCredentials credentials = GetCognitoAWSCredentials();

// Log identity changes
credentials.IdentityChangedEvent += (sender, args) =>
{
    Console.WriteLine("Identity changed: [{0}] => [{1}]", args.OldIdentityId, args.NewIdentityId);
};

using (var syncClient = new AmazonCognitoSyncClient(credentials))
{
    var result = syncClient.ListRecords(new ListRecordsRequest
    {
        DatasetName = datasetName
        // No need to specify these properties
        //IdentityId = "...",
        //IdentityPoolId = "..."        
    });
}
```

# Amazon CognitoAuthentication 延伸程式庫範例
<a name="cognito-authentication-extension"></a>

**注意**  
本主題中的資訊專屬於以 .NET Framework 和 3.3 適用於 .NET 的 AWS SDK 版及更早版本為基礎的專案。

CognitoAuthentication 延伸程式庫位於 [Amazon.Extensions.CognitoAuthentication](https://www.nuget.org/packages/Amazon.Extensions.CognitoAuthentication/) NuGet 套件中，可簡化 .NET Core 和 Xamarin 開發人員的 Amazon Cognito 使用者集區的身分驗證程序。程式庫建置在 Amazon Cognito Identity Provider API 之上，以建立和傳送使用者身分驗證 API 呼叫。

## 使用 CognitoAuthentication 延伸程式庫
<a name="using-the-cognitoauthentication-extension-library"></a>

Amazon Cognito 有一些標準身分驗證流程的內建 `AuthFlow` 和 `ChallengeName`值，可透過安全遠端密碼 (SRP) 驗證使用者名稱和密碼。如需有關驗證流量的詳細資訊，請參閱 [Amazon Cognito 使用者集區身分驗證流程 ](https://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-user-pools-authentication-flow.html)。

以下範例需要這些 `using` 陳述式：

```
// Required for all examples
using System;
using Amazon;
using Amazon.CognitoIdentity;
using Amazon.CognitoIdentityProvider;
using Amazon.Extensions.CognitoAuthentication;
using Amazon.Runtime;
// Required for the GetS3BucketsAsync example
using Amazon.S3;
using Amazon.S3.Model;
```

### 使用基本身分驗證
<a name="use-basic-authentication"></a>

使用 [AnonymousAWSCredentials](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/Runtime/TAnonymousAWSCredentials.html) 建立 [AmazonCognitoIdentityProviderClient](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/CognitoIdentityProvider/TCognitoIdentityProviderClient.html)，這不需要簽署的請求。您不需要提供一個區域。如果未提供區域，基本程式碼會呼叫 `FallbackRegionFactory.GetRegionEndpoint()`。建立 `CognitoUserPool` 和 `CognitoUser` 物件。以 `InitiateSrpAuthRequest` 呼叫 `StartWithSrpAuthAsync` 的方法，其中包含使用者密碼。

```
public static async void GetCredsAsync()
{
    AmazonCognitoIdentityProviderClient provider =
        new AmazonCognitoIdentityProviderClient(new Amazon.Runtime.AnonymousAWSCredentials());
    CognitoUserPool userPool = new CognitoUserPool("poolID", "clientID", provider);
    CognitoUser user = new CognitoUser("username", "clientID", userPool, provider);
    InitiateSrpAuthRequest authRequest = new InitiateSrpAuthRequest()
    {
        Password = "userPassword"
    };

    AuthFlowResponse authResponse = await user.StartWithSrpAuthAsync(authRequest).ConfigureAwait(false);
    accessToken = authResponse.AuthenticationResult.AccessToken;

}
```

### 利用挑戰進行驗證
<a name="authenticate-with-challenges"></a>

繼續挑戰驗證流程，例如使用 NewPasswordRequired 和 Multi-Factor Authentication (MFA)，也更簡易。唯一的需求是 CognitoAuthentication 物件、SRP 使用者的密碼和下次挑戰需要的資訊，需要在使用者輸入後取得提示。以下程式碼會在驗證流程中顯示一個方式來檢查挑戰類型、取得 MFA 的適當回應和 NewPasswordRequired 挑戰。

如同之前提出基本驗證請求，並且 `await` `AuthFlowResponse`。當透過傳回的 `AuthenticationResult` 物件收到循環回應時。如果 `ChallengeName` 類型為 `NEW_PASSWORD_REQUIRED`，呼叫 `RespondToNewPasswordRequiredAsync` 方法。

```
public static async void GetCredsChallengesAsync()
{
    AmazonCognitoIdentityProviderClient provider = 
        new AmazonCognitoIdentityProviderClient(new Amazon.Runtime.AnonymousAWSCredentials());
    CognitoUserPool userPool = new CognitoUserPool("poolID", "clientID", provider);
    CognitoUser user = new CognitoUser("username", "clientID", userPool, provider);
    InitiateSrpAuthRequest authRequest = new InitiateSrpAuthRequest(){
        Password = "userPassword"
    };

    AuthFlowResponse authResponse = await user.StartWithSrpAuthAsync(authRequest).ConfigureAwait(false);

    while (authResponse.AuthenticationResult == null)
    {
        if (authResponse.ChallengeName == ChallengeNameType.NEW_PASSWORD_REQUIRED)
        {
            Console.WriteLine("Enter your desired new password:");
            string newPassword = Console.ReadLine();

            authResponse = await user.RespondToNewPasswordRequiredAsync(new RespondToNewPasswordRequiredRequest()
            {
                SessionID = authResponse.SessionID,
                NewPassword = newPassword
            });
            accessToken = authResponse.AuthenticationResult.AccessToken;
        }
        else if (authResponse.ChallengeName == ChallengeNameType.SMS_MFA)
        {
            Console.WriteLine("Enter the MFA Code sent to your device:");
            string mfaCode = Console.ReadLine();

            AuthFlowResponse mfaResponse = await user.RespondToSmsMfaAuthAsync(new RespondToSmsMfaRequest()
            {
                SessionID = authResponse.SessionID,
                MfaCode = mfaCode

            }).ConfigureAwait(false);
            accessToken = authResponse.AuthenticationResult.AccessToken;
        }
        else
        {
            Console.WriteLine("Unrecognized authentication challenge.");
            accessToken = "";
            break;
        }
    }

    if (authResponse.AuthenticationResult != null)
    {
        Console.WriteLine("User successfully authenticated.");
    }
    else
    {
        Console.WriteLine("Error in authentication process.");
    }
 
}
```

### 身分驗證後使用 AWS 資源
<a name="use-aws-resources-after-authentication"></a>

使用 CognitoAuthentication 程式庫驗證使用者後，下一步是允許使用者存取適當的 AWS 資源。若要這樣做，您必須透過 Amazon Cognito 聯合身分主控台建立身分集區。透過指定您建立做為提供者的 Amazon Cognito 使用者集區，使用其 poolID 和 clientID，您可以允許 Amazon Cognito 使用者集區使用者存取 AWS 連接到您帳戶的資源。您也可以指定不同的角色，以啟用這兩種未經驗證及經過驗證的使用者存取不同的資源。您可以在 IAM 主控台變更這些規則，其中您可以新增或移除附加政策之角色的 **Action (動作)** 欄位的許可。然後，使用適當的身分集區、使用者集區和 Amazon Cognito 使用者資訊，您可以呼叫不同的 AWS 資源。下列範例顯示透過 SRP 驗證的使用者，存取關聯身分集區角色允許的不同 Amazon S3 儲存貯體

```
public async void GetS3BucketsAsync()
{
    var provider = new AmazonCognitoIdentityProviderClient(new AnonymousAWSCredentials());
    CognitoUserPool userPool = new CognitoUserPool("poolID", "clientID", provider);
    CognitoUser user = new CognitoUser("username", "clientID", userPool, provider);

    string password = "userPassword";

    AuthFlowResponse context = await user.StartWithSrpAuthAsync(new InitiateSrpAuthRequest()
    {
        Password = password
    }).ConfigureAwait(false);

    CognitoAWSCredentials credentials =
        user.GetCognitoAWSCredentials("identityPoolID", RegionEndpoint.< YourIdentityPoolRegion >);

    using (var client = new AmazonS3Client(credentials))
    {
        ListBucketsResponse response =
            await client.ListBucketsAsync(new ListBucketsRequest()).ConfigureAwait(false);

        foreach (S3Bucket bucket in response.Buckets)
        {
            Console.WriteLine(bucket.BucketName);
        }
    }
}
```

## 更多身分驗證選項
<a name="more-authentication-options"></a>

除了 SRP、NewPasswordRequired 和 MFA，CognitoAuthentication 擴展程式庫提供更輕鬆的驗證流程：
+ 自訂 - 以呼叫 `StartWithCustomAuthAsync(InitiateCustomAuthRequest customRequest)` 起始 
+ RefreshToken - 以呼叫 `StartWithRefreshTokenAuthAsync(InitiateRefreshTokenAuthRequest refreshTokenRequest)` 起始 
+ RefreshTokenSRP - 以呼叫 `StartWithRefreshTokenAuthAsync(InitiateRefreshTokenAuthRequest refreshTokenRequest)` 起始 
+ AdminNoSRP - 以呼叫 `StartWithAdminNoSrpAuthAsync(InitiateAdminNoSrpAuthRequest adminAuthRequest)` 起始 

根據您要的流程呼叫適當的方法。然後，當每個方法呼叫的 `AuthFlowResponse` 物件中顯示挑戰時，繼續提示使用者挑戰的存在。同時呼叫適當的回應方法，例如 `RespondToSmsMfaAuthAsync` 用於 MFA 挑戰，`RespondToCustomAuthAsync` 用於自訂挑戰。

# 使用 Amazon DynamoDB NoSQL 資料庫
<a name="dynamodb-intro"></a>

**注意**  
這些主題中的程式設計模型同時存在於 .NET Framework 和 .NET (Core) 中，但無論同步或非同步，呼叫慣例都不同。

 適用於 .NET 的 AWS SDK 支援 Amazon DynamoDB，這是 提供的快速 NoSQL 資料庫服務 AWS。開發套件提供三種與 DynamoDB 通訊的程式設計模型：*低階*模型、*文件*模型和*物件持久性*模型。

下列資訊介紹這些模型及其 APIs、提供如何使用和何時使用這些模型的範例，並為您提供 中其他 DynamoDB 程式設計資源的連結 適用於 .NET 的 AWS SDK。

## 低階模型
<a name="dynamodb-intro-apis-low-level"></a>

低階程式設計模型會包裝對 DynamoDB 服務的直接呼叫。您透過 [Amazon.DynamoDBv2](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/DynamoDBv2/NDynamoDBv2.html) 命名空間存取此模型。

三個模型中，低階模型要求您撰寫最多的程式碼。例如，您必須將 .NET 資料類型轉換為 DynamoDB 中的對等資料類型。不過，這個模型可讓您存取最多的功能。

下列範例示範如何使用低階模型來建立資料表、修改資料表，以及將項目插入 DynamoDB 中的資料表。

### 建立資料表
<a name="dynamodb-intro-apis-low-level-create-table"></a>

在下列範例中，您可以使用 `AmazonDynamoDBClient` 類別的 `CreateTable` 方法建立資料表。此 `CreateTable` 方法使用`CreateTableRequest` 類別的執行個體，其中包含特性，例如必要項目屬性名稱、主索引鍵定義和傳輸量。`CreateTable` 方法傳回 `CreateTableResponse` 類別的執行個體。

```
// using Amazon.DynamoDBv2;
// using Amazon.DynamoDBv2.Model;

var client = new AmazonDynamoDBClient();

Console.WriteLine("Getting list of tables");
List<string> currentTables = client.ListTables().TableNames;
Console.WriteLine("Number of tables: " + currentTables.Count);
if (!currentTables.Contains("AnimalsInventory"))
{
    var request = new CreateTableRequest
    {
        TableName = "AnimalsInventory",
        AttributeDefinitions = new List<AttributeDefinition>
      {
        new AttributeDefinition
        {
          AttributeName = "Id",
          // "S" = string, "N" = number, and so on.
          AttributeType = "N"
        },
        new AttributeDefinition
        {
          AttributeName = "Type",
          AttributeType = "S"
        }
      },
        KeySchema = new List<KeySchemaElement>
      {
        new KeySchemaElement
        {
          AttributeName = "Id",
          // "HASH" = hash key, "RANGE" = range key.
          KeyType = "HASH"
        },
        new KeySchemaElement
        {
          AttributeName = "Type",
          KeyType = "RANGE"
        },
      },
        ProvisionedThroughput = new ProvisionedThroughput
        {
            ReadCapacityUnits = 10,
            WriteCapacityUnits = 5
        },
    };

    var response = client.CreateTable(request);

    Console.WriteLine("Table created with request ID: " +
      response.ResponseMetadata.RequestId);
}
```

### 確認資料表已準備修改
<a name="dynamodb-intro-apis-low-level-verify-table"></a>

在您可以變更或修改資料表之前，資料表必須做好修改的準備。下列範例示範如何使用低階模型來驗證 DynamoDB 中的資料表是否已就緒。在這個範例中，透過 `AmazonDynamoDBClient` 類別的 `DescribeTable`方法來做為檢查目標資料表的參考。程式碼每 5 秒檢查一次資料表的 `TableStatus` 屬性值。當狀態是設定為 `ACTIVE`，資料表已準備好做修改。

```
// using Amazon.DynamoDBv2;
// using Amazon.DynamoDBv2.Model;

var client = new AmazonDynamoDBClient();      
var status = "";

do
{
  // Wait 5 seconds before checking (again).
  System.Threading.Thread.Sleep(TimeSpan.FromSeconds(5));
        
  try
  {
    var response = client.DescribeTable(new DescribeTableRequest
    {
      TableName = "AnimalsInventory"
    });

    Console.WriteLine("Table = {0}, Status = {1}",
      response.Table.TableName,
      response.Table.TableStatus);

    status = response.Table.TableStatus;
  }
  catch (ResourceNotFoundException)
  {
    // DescribeTable is eventually consistent. So you might
    //   get resource not found. 
  }

} while (status != TableStatus.ACTIVE);
```

### 將項目插入到資料表
<a name="dynamodb-intro-apis-low-level-insert-item"></a>

在下列範例中，您使用低階模型將兩個項目插入 DynamoDB 中的資料表。每個項目使用 `PutItemRequest` 類別的執行個體，透過 `AmazonDynamoDBClient` 類別的 `PutItem` 方法插入。`PutItemRequest` 類別的兩個執行個體的每一個，採用具有一系列的項目屬性值，且其項目將插入的資料表名稱。

```
// using Amazon.DynamoDBv2;
// using Amazon.DynamoDBv2.Model;

var client = new AmazonDynamoDBClient();

var request1 = new PutItemRequest
{
  TableName = "AnimalsInventory",
  Item = new Dictionary<string, AttributeValue>
  {
    { "Id", new AttributeValue { N = "1" }},
    { "Type", new AttributeValue { S = "Dog" }},
    { "Name", new AttributeValue { S = "Fido" }}
  }
};

var request2 = new PutItemRequest
{
  TableName = "AnimalsInventory",
  Item = new Dictionary<string, AttributeValue>
  {
    { "Id", new AttributeValue { N = "2" }},
    { "Type", new AttributeValue { S = "Cat" }},
    { "Name", new AttributeValue { S = "Patches" }}
  }
};
        
client.PutItem(request1);
client.PutItem(request2);
```

## 文件模型
<a name="dynamodb-intro-apis-document"></a>

文件程式設計模型提供更簡單的方法來使用 DynamoDB 中的資料。此模型特別適用於存取資料表和資料表中的項目。您透過 [Amazon.DynamoDBv2.DocumentModel](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/DynamoDBv2/NDynamoDBv2DocumentModel.html) 命名空間存取此模型。

與低階程式設計模型相比，文件模型更容易針對 DynamoDB 資料編寫程式碼。例如，您不需要在 DynamoDB 中將任意數量的 .NET 資料類型轉換為同等類型。不過，這個模型不提供如同低階程式設計模型數量一樣多功能的存取權。例如，您可以使用此模型來建立、擷取、更新和刪除資料表中的項目。不過，若要建立資料表，您必須使用低階模型。相較於物件持續性模型，這個模型要求您編寫更多的程式碼來存放、載入和查詢 .NET 物件。

如需 DynamoDB 文件程式設計模型的詳細資訊，請參閱《[Amazon DynamoDB 開發人員指南](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/)》中的 .[NET：文件模型](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DotNetSDKMidLevel.html)。

下列各節提供如何建立所需 DynamoDB 資料表之表示法的相關資訊，以及如何使用文件模型將項目插入資料表並從資料表取得項目的範例。

### 建立資料表的表示法
<a name="dynamodb-intro-apis-document-table"></a>

若要使用文件模型執行資料操作，您必須先建立代表特定資料表的 `Table`類別執行個體。有兩種主要方式可以執行此操作。

**LoadTable 方法**

第一個機制是使用 [https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/DynamoDBv2/TTable.html](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/DynamoDBv2/TTable.html)類別的其中一個靜態`LoadTable`方法，類似下列範例：

```
var client = new AmazonDynamoDBClient();
Table table = Table.LoadTable(client, "Reply");
```

**注意**  
雖然此機制可以運作，但在某些情況下，它有時可能會因為冷啟動和執行緒集區行為而導致額外的延遲或死結。如需這些行為的詳細資訊，請參閱部落格文章[改善 的 DynamoDB 初始化模式 適用於 .NET 的 AWS SDK](https://aws.amazon.com/blogs/developer/improved-dynamodb-initialization-patterns-for-the-aws-sdk-for-net/)。

**TableBuilder**

[AWSSDK.DynamoDBv2 NuGet 套件的 3.7.203 版](https://www.nuget.org/packages/AWSSDK.DynamoDBv2/3.7.203)中推出了替代機制 [https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/DynamoDBv2/TTableBuilder.html](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/DynamoDBv2/TTableBuilder.html)類別。此機制可以透過移除某些隱含方法呼叫來解決上述行為；特別是 `DescribeTable`方法。此機制的使用方式類似下列範例：

```
var client = new AmazonDynamoDBClient();
var table = new TableBuilder(client, "Reply")
    .AddHashKey("Id", DynamoDBEntryType.String)
    .AddRangeKey("ReplyDateTime", DynamoDBEntryType.String)
    .AddGlobalSecondaryIndex("PostedBy-Message-index", "Author", DynamoDBEntryType.String, "Message", DynamoDBEntryType.String)
    .Build();
```

如需此替代機制的詳細資訊，請再次參閱部落格文章[改善 的 DynamoDB 初始化模式 適用於 .NET 的 AWS SDK](https://aws.amazon.com/blogs/developer/improved-dynamodb-initialization-patterns-for-the-aws-sdk-for-net/)。

### 將項目插入資料表
<a name="dynamodb-intro-apis-document-insert-item"></a>

在下列範例中，回覆會透過 `Table`類別的 `PutItemAsync`方法插入回覆資料表。此 `PutItemAsync` 方法採用 `Document` 類別的執行個體； `Document` 類別只是一組初始化屬性。

```
using Amazon.DynamoDBv2;
using Amazon.DynamoDBv2.DocumentModel;

// Create a representation of the "Reply" table
//  by using one of the mechanisms described previously.

// Then, add a reply to the table.
var newReply = new Document();
newReply["Id"] = Guid.NewGuid().ToString();
newReply["ReplyDateTime"] = DateTime.UtcNow;
newReply["PostedBy"] = "Author1";
newReply["Message"] = "Thank you!";

await table.PutItemAsync(newReply);
```

### 從資料表取得項目
<a name="dynamodb-intro-apis-document-get-item"></a>

在下列範例中，會透過 `Table`類別的 `GetItemAsync`方法擷取回覆。為了判斷要取得的回覆， `GetItemAsync`方法會使用目標回覆的hash-and-range主索引鍵。

```
using Amazon.DynamoDBv2;
using Amazon.DynamoDBv2.DocumentModel;

// Create a representation of the "Reply" table
//  by using one of the mechanisms described previously.

// Then, get a reply from the table
//  where "guid" is the hash key and "datetime" is the range key.
var reply = await table.GetItemAsync(guid, datetime);
Console.WriteLine("Id = " + reply["Id"]);
Console.WriteLine("ReplyDateTime = " + reply["ReplyDateTime"]);
Console.WriteLine("PostedBy = " + reply["PostedBy"]);
Console.WriteLine("Message = " + reply["Message"]);
```

上述範例會隱含地將資料表值轉換為 `WriteLine` 方法的字串。您可以使用 `DynamoDBEntry`類別的各種「As【type】」方法進行明確轉換。例如，您可以透過 `AsGuid()`方法，將 的值`Id`從`Primitive`資料類型明確轉換為 GUID：

```
var guid = reply["Id"].AsGuid();
```

## 物件持續性模型
<a name="dynamodb-intro-apis-object-persistence"></a>

物件持久性程式設計模型專為在 DynamoDB 中存放、載入和查詢 .NET 物件而設計。您透過 [Amazon.DynamoDBv2.DataModel](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/DynamoDBv2/NDynamoDBv2DataModel.html) 命名空間存取此模型。

在三個模型中，每當您儲存、載入或查詢 DynamoDB 資料時，物件持久性模型最容易對 進行編碼。例如，您可以直接使用 DynamoDB 資料類型。不過，此模型只能存取在 DynamoDB 中存放、載入和查詢 .NET 物件的操作。例如，您可以使用此模型來建立、擷取、更新和刪除資料表中的項目。不過，您必須先使用低階模型建立資料表，然後使用此模型將 .NET 類別對應至資料表。

如需 DynamoDB 物件持久性程式設計模型的詳細資訊，請參閱《[Amazon DynamoDB 開發人員指南](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/)》中的 .[NET：物件持久性模型](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DotNetSDKHighLevel.html)。

下列範例示範如何定義代表 DynamoDB 項目的 .NET 類別、使用 .NET 類別的執行個體將項目插入 DynamoDB 資料表，以及使用 .NET 類別的執行個體從資料表取得項目。

### 定義代表資料表中項目的 .NET 類別
<a name="dynamodb-intro-apis-object-persistence-net-class-item"></a>

在下列類別定義範例中， `DynamoDBTable` 屬性會指定資料表名稱，而 `DynamoDBHashKey`和 `DynamoDBRangeKey` 屬性則會建立資料表hash-and-range主索引鍵的模型。`DynamoDBGlobalSecondaryIndexHashKey` 屬性已定義，因此可以建構特定作者的回覆查詢。

```
using Amazon.DynamoDBv2;
using Amazon.DynamoDBv2.DataModel;

[DynamoDBTable("Reply")]
public class Reply
{
    [DynamoDBHashKey]
    public string Id { get; set; }

    [DynamoDBRangeKey(StoreAsEpoch = false)]
    public DateTime ReplyDateTime { get; set; }

    [DynamoDBGlobalSecondaryIndexHashKey("PostedBy-Message-Index",
        AttributeName ="PostedBy")]
    public string Author { get; set; }

    [DynamoDBGlobalSecondaryIndexRangeKey("PostedBy-Message-Index")]
    public string Message { get; set; }
}
```

### 建立物件持久性模型的內容
<a name="dynamodb-intro-apis-object-persistence-context"></a>

若要使用 DynamoDB 的物件持久性程式設計模型，您必須建立內容，以提供與 DynamoDB 的連線，並可讓您存取資料表、執行各種操作和執行查詢。

**基本內容**

下列範例示範如何建立最基本的內容。

```
using Amazon.DynamoDBv2;
using Amazon.DynamoDBv2.DataModel;

var client = new AmazonDynamoDBClient();
var context = new DynamoDBContext(client);
```

**DisableFetchingTableMetadata 屬性的內容**

下列範例示範如何額外設定 `DynamoDBContextConfig`類別的 `DisableFetchingTableMetadata` 屬性，以防止對 `DescribeTable`方法的隱含呼叫。

```
using Amazon.DynamoDBv2;
using Amazon.DynamoDBv2.DataModel;

var client = new AmazonDynamoDBClient();
var context = new DynamoDBContext(client, new DynamoDBContextConfig
{
    DisableFetchingTableMetadata = true
});
```

如果 `DisableFetchingTableMetadata` 屬性設為 `false`（預設值），如第一個範例所示，您可以省略描述`Reply`類別中資料表項目索引鍵和索引結構的屬性。這些屬性將改為透過對 `DescribeTable`方法的隱含呼叫來推斷。如果 `DisableFetchingTableMetadata` 設定為 `true`，如第二個範例所示，物件持久性模型的方法，例如 `SaveAsync`和 完全`QueryAsync`依賴 `Reply`類別中定義的屬性。在此情況下，不會呼叫 `DescribeTable`方法。

**注意**  
在某些情況下，對 `DescribeTable`方法的呼叫有時可能會因為冷啟動和執行緒集區行為而導致額外的延遲或死結。因此，有時最好避免呼叫該方法。  
如需這些行為的詳細資訊，請參閱部落格文章[改善 的 DynamoDB 初始化模式 適用於 .NET 的 AWS SDK](https://aws.amazon.com/blogs/developer/improved-dynamodb-initialization-patterns-for-the-aws-sdk-for-net/)。

### 使用 .NET 類別的執行個體將項目插入資料表
<a name="dynamodb-intro-apis-object-persistence-net-insert-item"></a>

在此範例中，項目是透過 `DynamoDBContext`類別的 `SaveAsync`方法插入，這會取得代表項目之 .NET 類別的初始化執行個體。

```
using Amazon.DynamoDBv2;
using Amazon.DynamoDBv2.DataModel;

// Create an appropriate context for the object persistence programming model,
//  examples of which have been described earlier.

// Create an object that represents the new item.
var reply = new Reply()
{
    Id = Guid.NewGuid().ToString(),
    ReplyDateTime = DateTime.UtcNow,
    Author = "Author1",
    Message = "Thank you!"
};

// Insert the item into the table.
await context.SaveAsync<Reply>(reply, new DynamoDBOperationConfig
{
    IndexName = "PostedBy-Message-index"
});
```

### 使用 .NET 類別的執行個體從資料表取得項目
<a name="dynamodb-intro-apis-object-persistence-net-get-item"></a>

在此範例中，會建立查詢，以使用 `DynamoDBContext`類別的 `QueryAsync`方法尋找「Author1」的所有記錄。然後，透過查詢的 `GetNextSetAsync`方法擷取項目。

```
using Amazon.DynamoDBv2;
using Amazon.DynamoDBv2.DataModel;

// Create an appropriate context for the object persistence programming model,
//  examples of which have been described earlier.

// Construct a query that finds all replies by a specific author.
var query = context.QueryAsync<Reply>("Author1", new DynamoDBOperationConfig
{
    IndexName = "PostedBy-Message-index"
});

// Display the result.
var set = await query.GetNextSetAsync();
foreach (var item in set)
{
    Console.WriteLine("Id = " + item.Id);
    Console.WriteLine("ReplyDateTime = " + item.ReplyDateTime);
    Console.WriteLine("PostedBy = " + item.Author);
    Console.WriteLine("Message = " + item.Message);
}
```

### 物件持久性模型的其他資訊
<a name="dynamodb-intro-apis-object-persistence-more-into"></a>

上述範例和說明有時會包含名為 `DynamoDBContext`類別的屬性`DisableFetchingTableMetadata`。此屬性在 [ AWSSDK.DynamoDBv2 NuGet 套件的 3.7.203 版](https://www.nuget.org/packages/AWSSDK.DynamoDBv2/3.7.203)中推出，可讓您避免因冷啟動和執行緒集區行為而可能導致額外延遲或死結的特定情況。如需詳細資訊，請參閱部落格文章[改善 的 DynamoDB 初始化模式 適用於 .NET 的 AWS SDK](https://aws.amazon.com/blogs/developer/improved-dynamodb-initialization-patterns-for-the-aws-sdk-for-net/)。

以下是有關此屬性的一些額外資訊。
+ 如果您使用 .NET Framework，則可以在 `app.config`或 `web.config` 檔案中全域設定此屬性。
+ 您可以使用 [https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/Amazon/TAWSConfigsDynamoDB.html](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/Amazon/TAWSConfigsDynamoDB.html)類別全域設定此屬性，如下列範例所示。

  ```
  // Set the DisableFetchingTableMetadata property globally
  // before constructing any context objects.
  AWSConfigsDynamoDB.Context.DisableFetchingTableMetadata = true;
  
  var client = new AmazonDynamoDBClient();
  var context = new DynamoDBContext(client);
  ```
+ 在某些情況下，您無法將 DynamoDB 屬性新增至 .NET 類別；例如，如果類別是在相依性中定義。在這種情況下，仍然可以利用 `DisableFetchingTableMetadata` 屬性。若要這樣做，請在 `DisableFetchingTableMetadata` 屬性之外使用 [https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/DynamoDBv2/TTableBuilder.html](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/DynamoDBv2/TTableBuilder.html)類別。此`TableBuilder`類別也在 [ AWSSDK.DynamoDBv2 NuGet 套件的 3.7.203 版](https://www.nuget.org/packages/AWSSDK.DynamoDBv2/3.7.203)中推出。

  ```
  // Set the DisableFetchingTableMetadata property globally
  // before constructing any context objects.
  AWSConfigsDynamoDB.Context.DisableFetchingTableMetadata = true;
  
  var client = new AmazonDynamoDBClient();
  var context = new DynamoDBContext(client);
  
  var table = new TableBuilder(client, "Reply")
      .AddHashKey("Id", DynamoDBEntryType.String)
      .AddRangeKey("ReplyDateTime", DynamoDBEntryType.String)
      .AddGlobalSecondaryIndex("PostedBy-Message-index", "Author", DynamoDBEntryType.String,
          "Message", DynamoDBEntryType.String)
      .Build();
  
  // This registers the "Reply" table we constructed via the builder.
  context.RegisterTableDefinition(table);
  
  // Now operations like this will work,
  // even if the Reply class was not annotated with this index.
  var query = context.QueryAsync<Reply>("Author1", new DynamoDBOperationConfig()
  {
      IndexName = "PostedBy-Message-index"
  });
  ```

## 其他資訊
<a name="dynamodb-intro-more-info"></a>

 **使用 適用於 .NET 的 AWS SDK 來程式設計 DynamoDB、資訊和範例**
+  [DynamoDB API](http://blogs.aws.amazon.com/net/post/Tx17SQHVEMW8MXC/DynamoDB-APIs) 
+  [DynamoDB 系列開始](http://blogs.aws.amazon.com/net/post/Tx2XQOCY08QMTKO/DynamoDB-Series-Kickoff) 
+  [DynamoDB 系列 - 文件模型](http://blogs.aws.amazon.com/net/post/Tx2R0WG46GQI1JI/DynamoDB-Series-Document-Model) 
+  [DynamoDB 系列 - 轉換結構描述](http://blogs.aws.amazon.com/net/post/Tx2TCOGWG7ARUH5/DynamoDB-Series-Conversion-Schemas) 
+  [DynamoDB 系列 - 物件持久性模型](http://blogs.aws.amazon.com/net/post/Tx20L86FLMBW51P/DynamoDB-Series-Object-Persistence-Model) 
+  [DynamoDB 系列 - 運算式](http://blogs.aws.amazon.com/net/post/TxZQM7VA9AUZ9L/DynamoDB-Series-Expressions) 
+  [搭配 Amazon DynamoDB 和 使用運算式 適用於 .NET 的 AWS SDK](dynamodb-expressions.md) 
+  [Amazon DynamoDB 中的 JSON 支援](dynamodb-json.md) 

 **低階模型、資訊和範例** 
+  [使用 適用於 .NET 的 AWS SDK 低階 API 處理資料表](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/LowLevelDotNetWorkingWithTables.html) 
+  [使用 適用於 .NET 的 AWS SDK 低階 API 處理項目](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/LowLevelDotNetItemCRUD.html) 
+  [使用 適用於 .NET 的 AWS SDK 低階 API 查詢資料表](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/LowLevelDotNetQuerying.html) 
+  [使用 適用於 .NET 的 AWS SDK 低階 API 掃描資料表](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/LowLevelDotNetScanning.html) 
+  [使用 適用於 .NET 的 AWS SDK 低階 API 處理本機次要索引](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/LSILowLevelDotNet.html) 
+  [使用 適用於 .NET 的 AWS SDK 低階 API 處理全域次要索引](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GSILowLevelDotNet.html) 

 **文件模型、資訊和範例** 
+  [DynamoDB 資料類型 ](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DataModel.html#DataModel.DataTypes) 
+  [DynamoDBEntry](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/TDynamoDBv2DocumentModelDynamoDBEntry.html) 
+  [.NET：文件模型 ](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DotNetSDKMidLevel.html) 

 **物件持久性模型、資訊和範例** 
+  [.NET：物件持久性模型](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DotNetSDKHighLevel.html) 

 **其他實用資訊** 
+ [ AWS 與 .NET Acover 整合](aspire-integrations.md) 如需使用 Amazon DynamoDB 進行本機開發的相關資訊，請參閱 。

**Topics**
+ [

## 低階模型
](#dynamodb-intro-apis-low-level)
+ [

## 文件模型
](#dynamodb-intro-apis-document)
+ [

## 物件持續性模型
](#dynamodb-intro-apis-object-persistence)
+ [

## 其他資訊
](#dynamodb-intro-more-info)
+ [使用表達式](dynamodb-expressions.md)
+ [JSON 支援](dynamodb-json.md)

# 搭配 Amazon DynamoDB 和 使用運算式 適用於 .NET 的 AWS SDK
<a name="dynamodb-expressions"></a>

**注意**  
本主題中的資訊專屬於以 .NET Framework 和 3.3 適用於 .NET 的 AWS SDK 版及更早版本為基礎的專案。

下列程式碼範例示範如何使用 適用於 .NET 的 AWS SDK 搭配表達式來程式設計 DynamoDB。*運算式*表示您要從 DynamoDB 資料表中的項目讀取的屬性。您也可以在寫入項目時使用表達式來表示必須符合的任何條件 (也稱為*條件更新*) 及屬性的更新方式。有些更新範例是以新值取代屬性，或新增資料到清單或對應表。如需詳細資訊，請參閱[使用運算式讀取和寫入項目](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.html)。

**Topics**
+ [

## 範例資料
](#dynamodb-expressions-sample-data)
+ [

## 使用表達式和項目的主索引鍵取得單一項目
](#dynamodb-expressions-get-item)
+ [

## 使用表達式和資料表的主索引鍵取得多重項目
](#dynamodb-expressions-query)
+ [

## 使用運算式和其他項目屬性來取得多重項目
](#dynamodb-expressions-scan)
+ [

## 列印項目
](#dynamodb-expressions-print-item)
+ [

## 使用運算式建立或取代項目
](#dynamodb-expressions-put-item)
+ [

## 使用運算式更新項目
](#dynamodb-expressions-update-item)
+ [

## 使用運算式刪除項目
](#dynamodb-expressions-delete-item)
+ [

## 詳細資訊
](#dynamodb-expressions-resources)

## 範例資料
<a name="dynamodb-expressions-sample-data"></a>

本主題中的程式碼範例依賴名為 的 DynamoDB 資料表中的下列兩個範例項目`ProductCatalog`。這些項目描述有關產品項目存放在虛構自行車目錄的資訊。這些項目中提供的範例是根據 [案例研究：ProductCatalog 項目](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.CaseStudy.html)。資料類型描述項如 `BOOL`、`L`、`M`、`N`、`NS`、`S` 和 `SS`，對應到 [JSON 資料格式](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DataFormat.html)中的描述項。

```
{
  "Id": {
    "N": "205"
  },
  "Title": {
    "S": "20-Bicycle 205"
  },
  "Description": {
    "S": "205 description"
  },
  "BicycleType": {
    "S": "Hybrid"
  },
  "Brand": {
    "S": "Brand-Company C"
  },
  "Price": {
    "N": "500"
  },
  "Gender": {
    "S": "B"
  },
  "Color": {
    "SS": [
      "Red",
      "Black"
    ]
  },
  "ProductCategory": {
    "S": "Bike"
  },
  "InStock": {
    "BOOL": true
  },
  "QuantityOnHand": {
    "N": "1"
  },
  "RelatedItems": {
    "NS": [
      "341",
      "472",
      "649"
    ]
  },
  "Pictures": {
    "L": [
      {
        "M": {
          "FrontView": {
            "S": "http://example/products/205_front.jpg"
          }
        }
      },
      {
        "M": {
          "RearView": {
            "S": "http://example/products/205_rear.jpg"
          }
        }
      },
      {
        "M": {
          "SideView": {
            "S": "http://example/products/205_left_side.jpg"
          }
        }
      }
    ]
  },
  "ProductReviews": {
    "M": {
      "FiveStar": {
        "SS": [
          "Excellent! Can't recommend it highly enough! Buy it!",
          "Do yourself a favor and buy this."
        ]
      },
      "OneStar": {
        "SS": [
          "Terrible product! Do not buy this."
        ]
      }
    }
  }
},
{
  "Id": {
    "N": "301"
  },
  "Title": {
    "S": "18-Bicycle 301"
  },
  "Description": {
    "S": "301 description"
  },
  "BicycleType": {
    "S": "Road"
  },
  "Brand": {
    "S": "Brand-Company C"
  },
  "Price": {
    "N": "185"
  },
  "Gender": {
    "S": "F"
  },
  "Color": {
    "SS": [
      "Blue",
      "Silver"
    ]
  },
  "ProductCategory": {
    "S": "Bike"
  },
  "InStock": {
    "BOOL": true
  },
  "QuantityOnHand": {
    "N": "3"
  },
  "RelatedItems": {
    "NS": [
      "801",
      "822",
      "979"
    ]
  },
  "Pictures": {
    "L": [
      {
        "M": {
          "FrontView": {
            "S": "http://example/products/301_front.jpg"
          }
        }
      },
      {
        "M": {
          "RearView": {
            "S": "http://example/products/301_rear.jpg"
          }
        }
      },
      {
        "M": {
          "SideView": {
            "S": "http://example/products/301_left_side.jpg"
          }
        }
      }
    ]
  },
  "ProductReviews": {
    "M": {
      "FiveStar": {
        "SS": [
          "My daughter really enjoyed this bike!"
        ]
      },
      "ThreeStar": {
        "SS": [
          "This bike was okay, but I would have preferred it in my color.",
	      "Fun to ride."
        ]
      }
    }
  }
}
```

## 使用表達式和項目的主索引鍵取得單一項目
<a name="dynamodb-expressions-get-item"></a>

以下範例功能 `Amazon.DynamoDBv2.AmazonDynamoDBClient.GetItem` 方法和一組可取得並列印具有 `Id` 的 `205` 項目的運算式。只有下列項目的屬性會傳回：`Id`、`Title`、`Description`、`Color`、`RelatedItems`、`Pictures` 和 `ProductReviews`。

```
// using Amazon.DynamoDBv2;
// using Amazon.DynamoDBv2.Model;

var client = new AmazonDynamoDBClient();
var request = new GetItemRequest
{
  TableName = "ProductCatalog",
  ProjectionExpression = "Id, Title, Description, Color, #ri, Pictures, #pr",
  ExpressionAttributeNames = new Dictionary<string, string>
  {
    { "#pr", "ProductReviews" },
    { "#ri", "RelatedItems" }
  },
  Key = new Dictionary<string, AttributeValue>
  {
    { "Id", new AttributeValue { N = "205" } }
  },
};
var response = client.GetItem(request);

// PrintItem() is a custom function.
PrintItem(response.Item);
```

在上述範例中，`ProjectionExpression` 屬性指定要傳回的屬性。此 `ExpressionAttributeNames` 屬性指定預留位置 `#pr` 代表 `ProductReviews` 屬性，而預留位置 `#ri` 代表 `RelatedItems` 屬性。呼叫 `PrintItem` 是指在[列印項目](#dynamodb-expressions-print-item)中描述的自訂功能。

## 使用表達式和資料表的主索引鍵取得多重項目
<a name="dynamodb-expressions-query"></a>

以下範例具備 `Amazon.DynamoDBv2.AmazonDynamoDBClient.Query` 方法和一組可取得的運算式，然後列印具有 `Id` `301` 的項目，但只限於 `Price` 值大於 `150` 時。只有下列項目的屬性會傳回：`Id`、`Title` 和所有在 `ProductReviews` 的 `ThreeStar` 屬性。

```
// using Amazon.DynamoDBv2;
// using Amazon.DynamoDBv2.Model;

var client = new AmazonDynamoDBClient();
var request = new QueryRequest
{
  TableName = "ProductCatalog",
  KeyConditions = new Dictionary<string,Condition>
  {
    { "Id", new Condition()
      {
        ComparisonOperator = ComparisonOperator.EQ,
        AttributeValueList = new List<AttributeValue>
        {
          new AttributeValue { N = "301" }
        }
      }
    }
  },
  ProjectionExpression = "Id, Title, #pr.ThreeStar",
  ExpressionAttributeNames = new Dictionary<string, string>
  {
    { "#pr", "ProductReviews" },
    { "#p", "Price" }
  },
  ExpressionAttributeValues = new Dictionary<string,AttributeValue>
  {
    { ":val", new AttributeValue { N = "150" } }
  },
  FilterExpression = "#p > :val"
};
var response = client.Query(request);

foreach (var item in response.Items)
{
  // Write out the first page of an item's attribute keys and values.
  // PrintItem() is a custom function.
  PrintItem(item);
  Console.WriteLine("=====");
}
```

在上述範例中，`ProjectionExpression` 屬性指定要傳回的屬性。此 `ExpressionAttributeNames` 屬性指定預留位置 `#pr` 代表 `ProductReviews` 屬性，而預留位置 `#p` 代表 `Price` 屬性。`#pr.ThreeStar` 指定只傳回 `ThreeStar` 屬性。`ExpressionAttributeValues` 屬性指定預留位置 `:val` 代表值 `150`。`FilterExpression` 屬性指定 `#p` (`Price`) 必須大於 `:val` (`150`)。呼叫 `PrintItem` 是指在[列印項目](#dynamodb-expressions-print-item)中描述的自訂功能。

## 使用運算式和其他項目屬性來取得多重項目
<a name="dynamodb-expressions-scan"></a>

以下範例具備 `Amazon.DynamoDBv2.AmazonDynamoDBClient.Scan` 方法和一組可取得的運算式，然後列印所有具有 `Bike` 的 `ProductCategory` 項目。只有下列項目的屬性會傳回：`Id`、`Title` 和所有在 `ProductReviews` 的屬性。

```
// using Amazon.DynamoDBv2;
// using Amazon.DynamoDBv2.Model;

var client = new AmazonDynamoDBClient();
var request = new ScanRequest
{
  TableName = "ProductCatalog",
  ProjectionExpression = "Id, Title, #pr",
  ExpressionAttributeValues = new Dictionary<string,AttributeValue>
  {
    { ":catg", new AttributeValue { S = "Bike" } }
  },
  ExpressionAttributeNames = new Dictionary<string, string>
  {
    { "#pr", "ProductReviews" },
    { "#pc", "ProductCategory" }
  },
  FilterExpression = "#pc = :catg",  
};
var response = client.Scan(request);

foreach (var item in response.Items)
{
  // Write out the first page/scan of an item's attribute keys and values.
  // PrintItem() is a custom function.
  PrintItem(item);
  Console.WriteLine("=====");
}
```

在上述範例中，`ProjectionExpression` 屬性指定要傳回的屬性。此 `ExpressionAttributeNames` 屬性指定預留位置 `#pr` 代表 `ProductReviews` 屬性，而預留位置 `#pc` 代表 `ProductCategory` 屬性。`ExpressionAttributeValues` 屬性指定預留位置 `:catg` 代表值 `Bike`。`FilterExpression` 屬性指定 `#pc` (`ProductCategory`) 必須等於 `:catg` (`Bike`)。呼叫 `PrintItem` 是指在[列印項目](#dynamodb-expressions-print-item)中描述的自訂功能。

## 列印項目
<a name="dynamodb-expressions-print-item"></a>

以下範例說明如何列印某個項目的屬性和值。此範例用於上述範例，說明如何[使用表達式和項目的主索引鍵取得單一項目](#dynamodb-expressions-get-item)、[使用表達式和資料表的主索引鍵取得多重項目](#dynamodb-expressions-query)，以及[使用表達式和其他項目屬性取得多重項目](#dynamodb-expressions-scan)。

```
// using Amazon.DynamoDBv2.Model;

// Writes out an item's attribute keys and values.
public static void PrintItem(Dictionary<string, AttributeValue> attrs)
{
  foreach (KeyValuePair<string, AttributeValue> kvp in attrs)
  {
    Console.Write(kvp.Key + " = ");
    PrintValue(kvp.Value);
  }
}

// Writes out just an attribute's value.
public static void PrintValue(AttributeValue value)
{
  // Binary attribute value.
  if (value.B != null)
  {
    Console.Write("Binary data");
  }
  // Binary set attribute value.
  else if (value.BS.Count > 0)
  {
    foreach (var bValue in value.BS)
    {
      Console.Write("\n  Binary data");
    }
  }
  // List attribute value.
  else if (value.L.Count > 0)
  {
    foreach (AttributeValue attr in value.L)
    {
      PrintValue(attr);
    }
  }
  // Map attribute value.
  else if (value.M.Count > 0)
  {
    Console.Write("\n");
    PrintItem(value.M);
  }
  // Number attribute value.
  else if (value.N != null)
  {
    Console.Write(value.N);
  }
  // Number set attribute value.
  else if (value.NS.Count > 0)
  {
    Console.Write("{0}", string.Join("\n", value.NS.ToArray()));
  }
  // Null attribute value.
  else if (value.NULL)
  {
    Console.Write("Null");
  }
  // String attribute value.
  else if (value.S != null)
  {
    Console.Write(value.S);
  }
  // String set attribute value.
  else if (value.SS.Count > 0)
  {
    Console.Write("{0}", string.Join("\n", value.SS.ToArray()));
  }
  // Otherwise, boolean value.
  else
  {
    Console.Write(value.BOOL);
  }
 
  Console.Write("\n");
}
```

在上述範例中，每個屬性值有數種資料類型特定屬性，可進行評估以判斷列印屬性所用的正確格式。這些屬性包括 `B`、`BOOL`、`BS`、`L`、`M`、`N`、`NS`、`NULL`、`S` 和 `SS`，這些分別對應於那些[JSON 資料格式](DataFormat.html)。對於像 `B`、`N`、`NULL` 和 `S` 的屬性，如果對應的屬性不是 `null`，則屬性是對應的非 `null` 資料類型。對於，例如`BS`、`L`、`M`、`NS` 和 `SS` 屬性，如果 `Count` 大於零，則屬性是對應的非零值資料類型。如果所有屬性的資料類型特定屬性是 `null` 或 `Count` 等於零，則屬性對應到 `BOOL` 資料類型。

## 使用運算式建立或取代項目
<a name="dynamodb-expressions-put-item"></a>

以下範例具備 `Amazon.DynamoDBv2.AmazonDynamoDBClient.PutItem` 方法和一組可取得的運算式，可更新具有 `18-Bicycle 301` 的 `Title` 的項目。如果項目尚未存在，則會新增新的項目。

```
// using Amazon.DynamoDBv2;
// using Amazon.DynamoDBv2.Model;

var client = new AmazonDynamoDBClient();
var request = new PutItemRequest
{
  TableName = "ProductCatalog",
  ExpressionAttributeNames = new Dictionary<string, string>
  {
    { "#title", "Title" }
  },
  ExpressionAttributeValues = new Dictionary<string, AttributeValue>
  {
    { ":product", new AttributeValue { S = "18-Bicycle 301" } }
  },
  ConditionExpression = "#title = :product", 
  // CreateItemData() is a custom function.
  Item = CreateItemData()
};
client.PutItem(request);
```

在上述範例中，`ExpressionAttributeNames` 屬性指定預留位置 `#title` 代表 `Title` 屬性。`ExpressionAttributeValues` 屬性指定預留位置 `:product` 代表值 `18-Bicycle 301`。`ConditionExpression` 屬性指定 `#title` (`Title`) 必須等於 `:product` (`18-Bicycle 301`)。此呼叫 `CreateItemData` 是指以下自訂函數：

```
// using Amazon.DynamoDBv2.Model;

// Provides a sample item that can be added to a table.
public static Dictionary<string, AttributeValue> CreateItemData()
{
  var itemData = new Dictionary<string, AttributeValue>
  {
    { "Id", new AttributeValue { N = "301" } },
    { "Title", new AttributeValue { S = "18\" Girl's Bike" } },
    { "BicycleType", new AttributeValue { S = "Road" } },
    { "Brand" , new AttributeValue { S = "Brand-Company C" } },
    { "Color", new AttributeValue { SS = new List<string>{ "Blue", "Silver" } } },
    { "Description", new AttributeValue { S = "301 description" } },
    { "Gender", new AttributeValue { S = "F" } },
    { "InStock", new AttributeValue { BOOL = true } },
    { "Pictures", new AttributeValue { L = new List<AttributeValue>{ 
      { new AttributeValue { M = new Dictionary<string,AttributeValue>{
        { "FrontView", new AttributeValue { S = "http://example/products/301_front.jpg" } } } } },
      { new AttributeValue { M = new Dictionary<string,AttributeValue>{
        { "RearView", new AttributeValue {S = "http://example/products/301_rear.jpg" } } } } },
      { new AttributeValue { M = new Dictionary<string,AttributeValue>{
        { "SideView", new AttributeValue { S = "http://example/products/301_left_side.jpg" } } } } }
    } } },
    { "Price", new AttributeValue { N = "185" } },
    { "ProductCategory", new AttributeValue { S = "Bike" } },
    { "ProductReviews", new AttributeValue { M = new Dictionary<string,AttributeValue>{
      { "FiveStar", new AttributeValue { SS = new List<string>{
        "My daughter really enjoyed this bike!" } } },
      { "OneStar", new AttributeValue { SS = new List<string>{
        "Fun to ride.",
        "This bike was okay, but I would have preferred it in my color." } } }
    } } },
    { "QuantityOnHand", new AttributeValue { N = "3" } },
    { "RelatedItems", new AttributeValue { NS = new List<string>{ "979", "822", "801" } } }
  };

  return itemData;
}
```

在上述範例中，具範例資料的範例項目會傳回給呼叫者。建構一系列屬性和對應的值，使用資料類型例如 `BOOL`、`L`、`M`、`N`、`NS`、`S`、和`SS`、分別對應於那些 [JSON 資料格式](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DataFormat.html)。

## 使用運算式更新項目
<a name="dynamodb-expressions-update-item"></a>

以下範例具備 `Amazon.DynamoDBv2.AmazonDynamoDBClient.UpdateItem` 方法和一組運算式，為具有 `Id` `301` 的項目變更 `Title` 到 `18" Girl's Bike`。

```
// using Amazon.DynamoDBv2;
// using Amazon.DynamoDBv2.Model;

var client = new AmazonDynamoDBClient();
var request = new UpdateItemRequest
{
  TableName = "ProductCatalog",
  Key = new Dictionary<string,AttributeValue>
  {
     { "Id", new AttributeValue { N = "301" } }
  },
  ExpressionAttributeNames = new Dictionary<string, string>
  {
    { "#title", "Title" }
  },
  ExpressionAttributeValues = new Dictionary<string, AttributeValue>
  {
    { ":newproduct", new AttributeValue { S = "18\" Girl's Bike" } }
  },
  UpdateExpression = "SET #title = :newproduct"
};
client.UpdateItem(request);
```

在上述範例中，`ExpressionAttributeNames` 屬性指定預留位置 `#title` 代表 `Title` 屬性。`ExpressionAttributeValues` 屬性指定預留位置 `:newproduct` 代表值 `18" Girl's Bike`。`UpdateExpression` 屬性指定變更 `#title` (`Title`) 為 `:newproduct` (`18" Girl's Bike`)。

## 使用運算式刪除項目
<a name="dynamodb-expressions-delete-item"></a>

以下範例具備 `Amazon.DynamoDBv2.AmazonDynamoDBClient.DeleteItem` 方法和一組表達式，可刪除具有 `Id` `301` 的項目，但只有項目的 `Title` 為 `18-Bicycle 301`。

```
// using Amazon.DynamoDBv2;
// using Amazon.DynamoDBv2.Model;

var client = new AmazonDynamoDBClient();
var request = new DeleteItemRequest
{
  TableName = "ProductCatalog",
  Key = new Dictionary<string,AttributeValue>
  {
     { "Id", new AttributeValue { N = "301" } }
  },
  ExpressionAttributeNames = new Dictionary<string, string>
  {
    { "#title", "Title" }
  },
  ExpressionAttributeValues = new Dictionary<string, AttributeValue>
  {
    { ":product", new AttributeValue { S = "18-Bicycle 301" } }
  },
  ConditionExpression = "#title = :product"
};
client.DeleteItem(request);
```

在上述範例中，`ExpressionAttributeNames` 屬性指定預留位置 `#title` 代表 `Title` 屬性。`ExpressionAttributeValues` 屬性指定預留位置 `:product` 代表值 `18-Bicycle 301`。`ConditionExpression` 屬性指定 `#title` (`Title`) 必須等於 `:product` (`18-Bicycle 301`)。

## 詳細資訊
<a name="dynamodb-expressions-resources"></a>

如需詳細資訊和編碼範例，請參閱:
+  [DynamoDB 系列 - 運算式](http://blogs.aws.amazon.com/net/post/TxZQM7VA9AUZ9L/DynamoDB-Series-Expressions) 
+  [ 存取項目的投影運算式屬性 ](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.AccessingItemAttributes.html) 
+  [ 使用預留位置的屬性名稱和值](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/ExpressionPlaceholders.html) 
+  [使用條件運算式指定條件](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.SpecifyingConditions.html) 
+  [以更新運算式修改項目和屬性](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.Modifying.html) 
+  [使用 適用於 .NET 的 AWS SDK 低階 API 處理項目](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/LowLevelDotNetItemCRUD.html) 
+  [使用 適用於 .NET 的 AWS SDK 低階 API 查詢資料表](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/LowLevelDotNetQuerying.html) 
+  [使用 適用於 .NET 的 AWS SDK 低階 API 掃描資料表](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/LowLevelDotNetScanning.html) 
+  [使用 適用於 .NET 的 AWS SDK 低階 API 處理本機次要索引](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/LSILowLevelDotNet.html) 
+  [使用 適用於 .NET 的 AWS SDK 低階 API 處理全域次要索引](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GSILowLevelDotNet.html) 

# Amazon DynamoDB 中的 JSON 支援
<a name="dynamodb-json"></a>

**注意**  
本主題中的資訊專屬於以 .NET Framework 和 3.3 適用於 .NET 的 AWS SDK 版及更早版本為基礎的專案。

使用 Amazon DynamoDB 時， 適用於 .NET 的 AWS SDK 支援 JSON 資料。這可讓您更輕鬆地從 DynamoDB 資料表取得 JSON 格式的資料，並將 JSON 文件插入其中。

**Topics**
+ [

## 以 JSON 格式從 DynamoDB 資料表取得資料
](#dynamodb-json-get-table-data)
+ [

## 將 JSON 格式資料插入 DynamoDB 資料表
](#dynamodb-json-insert-table-data)
+ [

## DynamoDB 資料類型轉換為 JSON
](#dynamodb-json-datatypes)
+ [

## 詳細資訊
](#dynamodb-json-more-info)

## 以 JSON 格式從 DynamoDB 資料表取得資料
<a name="dynamodb-json-get-table-data"></a>

下列範例顯示如何從 DynamoDB 資料表取得 JSON 格式的資料：

```
// using Amazon.DynamoDBv2;
// using Amazon.DynamoDBv2.DocumentModel;

var client = new AmazonDynamoDBClient();
var table = Table.LoadTable(client, "AnimalsInventory");
var item = table.GetItem(3, "Horse");

var jsonText = item.ToJson();
Console.Write(jsonText);
      
// Output:
//   {"Name":"Shadow","Type":"Horse","Id":3}

var jsonPrettyText = item.ToJsonPretty();
Console.WriteLine(jsonPrettyText);
      
// Output:
//   {
//     "Name" : "Shadow",
//     "Type" : "Horse",
//     "Id"   : 3
//   }
```

在上述範例中，`Document` 類別的 `ToJson` 方法將某個項目從資料表轉換到 JSON 格式字串。該項目透過 `Table` 類別的 `GetItem` 方法擷取。在此範例中，為判斷要取得的項目，`GetItem` 方法使用目標項目的雜湊和範圍主索引鍵。為了決定要從中取得項目的資料表， `Table` 類別的 `LoadTable`方法會使用 DynamoDB 中 `AmazonDynamoDBClient`類別的執行個體和目標資料表的名稱。

## 將 JSON 格式資料插入 DynamoDB 資料表
<a name="dynamodb-json-insert-table-data"></a>

下列範例示範如何使用 JSON 格式將項目插入 DynamoDB 資料表：

```
// using Amazon.DynamoDBv2;
// using Amazon.DynamoDBv2.DocumentModel;

var client = new AmazonDynamoDBClient();
var table = Table.LoadTable(client, "AnimalsInventory");
var jsonText = "{\"Id\":6,\"Type\":\"Bird\",\"Name\":\"Tweety\"}";
var item = Document.FromJson(jsonText);

table.PutItem(item);
```

在上述範例中，`Document` 類別的 `FromJson` 方法將 JSON 格式字串轉換到項目。項目是透過 `Table` 類別的 `PutItem` 方法插入到資料表中，其使用包含項目的 `Document` 類別的執行個體。若要判斷要插入項目的資料表，會呼叫 `Table`類別的 `LoadTable` 方法，在 DynamoDB 中指定 `AmazonDynamoDBClient`類別的執行個體和目標資料表的名稱。

## DynamoDB 資料類型轉換為 JSON
<a name="dynamodb-json-datatypes"></a>

每當您呼叫 `Document`類別的 `ToJson`方法，然後在產生的 JSON 資料上呼叫 `FromJson`方法，將 JSON 資料轉換回`Document`類別的執行個體時，某些 DynamoDB 資料類型將不會如預期轉換。具體而言：
+ DynamoDB 集合 (`SS`、 `NS`和 `BS`類型） 將轉換為 JSON 陣列。
+ DynamoDB 二進位純量和集 ( `B`和 `BS`類型） 將轉換為 base64 編碼的 JSON 字串或字串清單。

  在此案例中，您必須呼叫的 `Document` 類別的 `DecodeBase64Attributes` 方法，使用正確的二進位代碼取代以 base64 編碼的 JSON 資料。在以下範例中，在名為 `Picture` 之 `Document` 類別的執行個體中，使用正確的二進位代碼取代以 base64 編碼的二進位純量項目屬性。此範例也在名為 `RelatedPictures` 之 `Document` 類別的相同執行個體中，針對以 base64 編碼的二進位集項目屬性進行目同操作：

  ```
  item.DecodeBase64Attributes("Picture", "RelatedPictures");
  ```

## 詳細資訊
<a name="dynamodb-json-more-info"></a>

如需使用 DynamoDB 搭配 對 JSON 進行程式設計的詳細資訊和範例 適用於 .NET 的 AWS SDK，請參閱：
+  [DynamoDB JSON 支援](https://aws.amazon.com/blogs/developer/dynamodb-json-support/) 
+  [Amazon DynamoDB 更新 - JSON、擴充免費方案、靈活擴展、較大項目](https://aws.amazon.com/blogs/aws/dynamodb-update-json-and-more/) 

# 使用 Amazon EC2
<a name="ec2-apis-intro"></a>

 適用於 .NET 的 AWS SDK 支援 [Amazon EC2](https://docs.aws.amazon.com/ec2/)，這是一種 Web 服務，可提供可調整大小的運算容量。您可以使用此運算容量來建置和託管軟體系統。

## API
<a name="w2aac19c15c17b5"></a>

為 Amazon EC2 用戶端 適用於 .NET 的 AWS SDK 提供 APIs。APIs 可讓您使用安全群組和金鑰對等 EC2 功能。APIs 也可讓您控制 Amazon EC2 執行個體。本節包含一些範例，顯示您在使用這些 APIs 時可遵循的模式。若要檢視完整的 APIs 集，請參閱 [適用於 .NET 的 AWS SDK API 參考](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/) （並捲動至「Amazon.EC2」)。

Amazon EC2 APIs 由 [AWSSDK.EC2](https://www.nuget.org/packages/AWSSDK.EC2) NuGet 套件提供。

## 先決條件
<a name="w2aac19c15c17b7"></a>

開始之前，請確定您已[設定環境和專案](net-dg-config.md)。也請檢閱 中的資訊[開發套件功能](net-dg-sdk-features.md)。

## 關於範例
<a name="ec2-apis-intro-about"></a>

本節中的範例說明如何使用 Amazon EC2 用戶端和管理 Amazon EC2 執行個體。

[EC2 Spot 執行個體教學](how-to-spot-instances.md)課程說明如何請求 Amazon EC2 Spot 執行個體。Spot 執行個體可讓您以低於隨需價格的價格存取未使用的 EC2 容量。

**Topics**
+ [

## API
](#w2aac19c15c17b5)
+ [

## 先決條件
](#w2aac19c15c17b7)
+ [

## 關於範例
](#ec2-apis-intro-about)
+ [Security groups (安全群組)](security-groups.md)
+ [金鑰對](key-pairs.md)
+ [區域與可用區域](using-regions-and-availability-zones.md)
+ [EC2 執行個體](how-to-ec2.md)
+ [Spot 執行個體教學課程](how-to-spot-instances.md)

# 在 Amazon EC2 中使用安全群組
<a name="security-groups"></a>

在 Amazon EC2 中，*安全群組*可做為虛擬防火牆，控制一或多個 EC2 執行個體的網路流量。根據預設，EC2 會將您的執行個體與不允許傳入流量的安全群組建立關聯。您可以建立允許您的 EC2 執行個體接受特定連接的安全群組。例如，如果您需要連接到 EC2 Windows 執行個體，則必須設定安全群組以允許 RDP 流量。

若要進一步了解安全群組，請參閱[《Amazon EC2 使用者指南》中的 Amazon EC2 安全群組](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-security-groups.html)。 [Amazon EC2 ](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/)

**警告**  
EC2-Classic 在 2022 年 8 月 15 日淘汰。建議您從 EC2-Classic 遷移至 VPC。如需詳細資訊，請參閱部落格文章 [EC2-Classic Networking 正在淘汰 – 以下是如何準備](https://aws.amazon.com/blogs/aws/ec2-classic-is-retiring-heres-how-to-prepare/)。

如需 APIs和先決條件的相關資訊，請參閱父區段 ([使用 Amazon EC2](ec2-apis-intro.md))。

**Topics**
+ [

# 列舉安全群組
](enumerate-security-groups.md)
+ [

# 建立安全群組
](creating-security-group.md)
+ [

# 更新安全群組
](authorize-ingress.md)

# 列舉安全群組
<a name="enumerate-security-groups"></a>

此範例說明如何使用 適用於 .NET 的 AWS SDK 列舉安全群組。如果您提供 [Amazon Virtual Private Cloud](https://docs.aws.amazon.com/vpc/latest/userguide/) ID，應用程式會列舉該特定 VPC 的安全群組。否則，應用程式只會顯示所有可用安全群組的清單。

下列各節提供此範例的程式碼片段。之後會顯示[範例的完整程式碼](#enum-sec-groups-complete-code)，並可依原樣建置和執行。

**Topics**
+ [

## 列舉安全群組
](#enum-sec-groups-enum)
+ [

## 完成程式碼
](#enum-sec-groups-complete-code)
+ [

## 其他考量
](#enum-sec-groups-additional)

## 列舉安全群組
<a name="enum-sec-groups-enum"></a>

下列程式碼片段會列舉您的安全群組。如果指定一個群組，則會列舉特定 VPC 的所有群組或群組。

[本主題結尾](#enum-sec-groups-complete-code)的範例顯示此程式碼片段正在使用中。

```
    //
    // Method to enumerate the security groups
    private static async Task EnumerateGroups(IAmazonEC2 ec2Client, string vpcID)
    {
      // A request object, in case we need it.
      var request = new DescribeSecurityGroupsRequest();

      // Put together the properties, if needed
      if(!string.IsNullOrEmpty(vpcID))
      {
        // We have a VPC ID. Find the security groups for just that VPC.
        Console.WriteLine($"\nGetting security groups for VPC {vpcID}...\n");
        request.Filters.Add(new Filter
        {
          Name = "vpc-id",
          Values = new List<string>() { vpcID }
        });
      }

      // Get the list of security groups
      DescribeSecurityGroupsResponse response =
        await ec2Client.DescribeSecurityGroupsAsync(request);

      // Display the list of security groups.
      foreach (SecurityGroup item in response.SecurityGroups)
      {
        Console.WriteLine("Security group: " + item.GroupId);
        Console.WriteLine("\tGroupId: " + item.GroupId);
        Console.WriteLine("\tGroupName: " + item.GroupName);
        Console.WriteLine("\tVpcId: " + item.VpcId);
        Console.WriteLine();
      }
    }
```

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

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

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

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

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

  [AmazonEC2Client](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TEC2Client.html) 類別
+ 命名空間 [Amazon.EC2.Model](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/NEC2Model.html)

  類別 [DescribeSecurityGroupsRequest](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TDescribeSecurityGroupsRequest.html)

  類別 [DescribeSecurityGroupsResponse](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TDescribeSecurityGroupsResponse.html)

  類別[篩選條件](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TFilter.html)

  類別 [SecurityGroup](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TSecurityGroup.html)

### 程式碼
<a name="w2aac19c15c17c13c13c15b7b1"></a>

```
using System;
using System.Threading.Tasks;
using System.Collections.Generic;
using Amazon.EC2;
using Amazon.EC2.Model;

namespace EC2EnumerateSecGroups
{
  class Program
  {
    static async Task Main(string[] args)
    {
      // Parse the command line
       string vpcID = string.Empty;
      if(args.Length == 0)
      {
        Console.WriteLine("\nEC2EnumerateSecGroups [vpc_id]");
        Console.WriteLine("  vpc_id - The ID of the VPC for which you want to see security groups.");
        Console.WriteLine("\nSince you specified no arguments, showing all available security groups.");
      }
      else
      {
        vpcID = args[0];
      }

      if(vpcID.StartsWith("vpc-") || string.IsNullOrEmpty(vpcID))
      {
        // Create an EC2 client object
        var ec2Client = new AmazonEC2Client();

        // Enumerate the security groups
        await EnumerateGroups(ec2Client, vpcID);
      }
      else
      {
        Console.WriteLine("Could not find a valid VPC ID in the command-line arguments:");
        Console.WriteLine($"{args[0]}");
      }
    }


    //
    // Method to enumerate the security groups
    private static async Task EnumerateGroups(IAmazonEC2 ec2Client, string vpcID)
    {
      // A request object, in case we need it.
      var request = new DescribeSecurityGroupsRequest();

      // Put together the properties, if needed
      if(!string.IsNullOrEmpty(vpcID))
      {
        // We have a VPC ID. Find the security groups for just that VPC.
        Console.WriteLine($"\nGetting security groups for VPC {vpcID}...\n");
        request.Filters.Add(new Filter
        {
          Name = "vpc-id",
          Values = new List<string>() { vpcID }
        });
      }

      // Get the list of security groups
      DescribeSecurityGroupsResponse response =
        await ec2Client.DescribeSecurityGroupsAsync(request);

      // Display the list of security groups.
      foreach (SecurityGroup item in response.SecurityGroups)
      {
        Console.WriteLine("Security group: " + item.GroupId);
        Console.WriteLine("\tGroupId: " + item.GroupId);
        Console.WriteLine("\tGroupName: " + item.GroupName);
        Console.WriteLine("\tVpcId: " + item.VpcId);
        Console.WriteLine();
      }
    }
  }
}
```

## 其他考量
<a name="enum-sec-groups-additional"></a>
+ 請注意，VPC 案例的篩選條件建構時，名稱/值對`Name`的部分設定為 "vpc-id"。此名稱來自 [DescribeSecurityGroupsRequest](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TDescribeSecurityGroupsRequest.html) 類別`Filters`屬性的描述。
+ 若要取得安全群組的完整清單，您也可以在沒有[參數的情況下使用 DescribeSecurityGroupsAsync](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/MEC2DescribeSecurityGroupsAsyncCancellationToken.html)。
+ 您可以在 [Amazon EC2 主控台](https://console.aws.amazon.com/ec2/v2/home#SecurityGroups)中檢查安全群組清單來驗證結果。

# 建立安全群組
<a name="creating-security-group"></a>

此範例說明如何使用 適用於 .NET 的 AWS SDK 來建立安全群組。您可以提供現有 VPC 的 ID，以在 VPC 中建立 EC2 的安全群組。如果您未提供此類 ID，如果 AWS 您的帳戶支援此 ID，則新的安全群組將適用於 EC2-Classic。

如果您未提供 VPC ID，且 AWS 您的帳戶不支援 EC2-Classic，則新的安全群組將屬於您帳戶的預設 VPC。

**警告**  
EC2-Classic 在 2022 年 8 月 15 日淘汰。建議您從 EC2-Classic 遷移至 VPC。如需詳細資訊，請參閱部落格文章 [EC2-Classic Networking 正在淘汰 – 以下是如何準備](https://aws.amazon.com/blogs/aws/ec2-classic-is-retiring-heres-how-to-prepare/)。

下列各節提供此範例的程式碼片段。之後會顯示[範例的完整程式碼](#create-sec-groups-complete-code)，並可依原樣建置和執行。

**Topics**
+ [

## 尋找現有的安全群組
](#create-sec-groups-find)
+ [

## 建立安全群組
](#create-sec-groups-enum)
+ [

## 完成程式碼
](#create-sec-groups-complete-code)

## 尋找現有的安全群組
<a name="create-sec-groups-find"></a>

下列程式碼片段會搜尋指定 VPC 中具有指定名稱的現有安全群組。

[本主題結尾](#create-sec-groups-complete-code)的範例顯示此程式碼片段正在使用中。

```
    //
    // Method to determine if a security group with the specified name
    // already exists in the VPC
    private static async Task<List<SecurityGroup>> FindSecurityGroups(
      IAmazonEC2 ec2Client, string groupName, string vpcID)
    {
      var request = new DescribeSecurityGroupsRequest();
      request.Filters.Add(new Filter{
        Name = "group-name",
        Values = new List<string>() { groupName }
      });
      if(!string.IsNullOrEmpty(vpcID))
        request.Filters.Add(new Filter{
          Name = "vpc-id",
          Values = new List<string>() { vpcID }
        });

      var response = await ec2Client.DescribeSecurityGroupsAsync(request);
      return response.SecurityGroups;
    }
```

## 建立安全群組
<a name="create-sec-groups-enum"></a>

如果指定 VPC 中不存在具有該名稱的群組，以下程式碼片段會建立新的安全群組。如果未指定 VPC，且具有該名稱的一或多個群組存在，則程式碼片段只會傳回群組清單。

[本主題結尾](#create-sec-groups-complete-code)的範例顯示此程式碼片段正在使用中。

```
    //
    // Method to create a new security group (either EC2-Classic or EC2-VPC)
    // If vpcID is empty, the security group will be for EC2-Classic
    private static async Task<List<SecurityGroup>> CreateSecurityGroup(
      IAmazonEC2 ec2Client, string groupName, string vpcID)
    {
      // See if one or more security groups with that name
      // already exist in the given VPC. If so, return the list of them.
      var securityGroups = await FindSecurityGroups(ec2Client, groupName, vpcID);
      if (securityGroups.Count > 0)
      {
        Console.WriteLine(
          $"\nOne or more security groups with name {groupName} already exist.\n");
        return securityGroups;
      }

      // If the security group doesn't already exists, create it.
      var createRequest = new CreateSecurityGroupRequest{
        GroupName = groupName
      };
      if(string.IsNullOrEmpty(vpcID))
      {
        createRequest.Description = "My .NET example security group for EC2-Classic";
      }
      else
      {
        createRequest.VpcId = vpcID;
        createRequest.Description = "My .NET example security group for EC2-VPC";
      }
      CreateSecurityGroupResponse createResponse =
        await ec2Client.CreateSecurityGroupAsync(createRequest);

      // Return the new security group
      DescribeSecurityGroupsResponse describeResponse =
        await ec2Client.DescribeSecurityGroupsAsync(new DescribeSecurityGroupsRequest{
          GroupIds = new List<string>() { createResponse.GroupId }
        });
      return describeResponse.SecurityGroups;
    }
```

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

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

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

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

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

  [AmazonEC2Client](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TEC2Client.html) 類別
+ 命名空間 [Amazon.EC2.Model](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/NEC2Model.html)

  類別 [CreateSecurityGroupRequest](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TCreateSecurityGroupRequest.html)

  類別 [CreateSecurityGroupResponse](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TCreateSecurityGroupResponse.html)

  類別 [DescribeSecurityGroupsRequest](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TDescribeSecurityGroupsRequest.html)

  類別 [DescribeSecurityGroupsResponse](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TDescribeSecurityGroupsResponse.html)

  類別[篩選條件 ](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TFilter.html)

  類別 [SecurityGroup](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TSecurityGroup.html)

### 程式碼
<a name="w2aac19c15c17c13c15c23b7b1"></a>

```
using System;
using System.Threading.Tasks;
using System.Collections.Generic;
using Amazon.EC2;
using Amazon.EC2.Model;

namespace EC2CreateSecGroup
{
  // = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
  // Class to create a security group
  class Program
  {
    private const int MaxArgs = 2;

    static async Task Main(string[] args)
    {
      // Parse the command line and show help if necessary
      var parsedArgs = CommandLine.Parse(args);
      if(parsedArgs.Count == 0)
      {
        PrintHelp();
        return;
      }
      if(parsedArgs.Count > MaxArgs)
        CommandLine.ErrorExit("\nThe number of command-line arguments is incorrect." +
          "\nRun the command with no arguments to see help.");

      // Get the application arguments from the parsed list
      var groupName = CommandLine.GetArgument(parsedArgs, null, "-g", "--group-name");
      var vpcID = CommandLine.GetArgument(parsedArgs, null, "-v", "--vpc-id");
      if(string.IsNullOrEmpty(groupName))
        CommandLine.ErrorExit("\nYou must supply a name for the new group." +
          "\nRun the command with no arguments to see help.");
      if(!string.IsNullOrEmpty(vpcID) && !vpcID.StartsWith("vpc-"))
        CommandLine.ErrorExit($"\nNot a valid VPC ID: {vpcID}");

      // groupName has a value and vpcID either has a value or is null (which is fine)
      // Create the new security group and display information about it
      var securityGroups =
        await CreateSecurityGroup(new AmazonEC2Client(), groupName, vpcID);
      Console.WriteLine("Information about the security group(s):");
      foreach(var group in securityGroups)
      {
        Console.WriteLine($"\nGroupName: {group.GroupName}");
        Console.WriteLine($"GroupId: {group.GroupId}");
        Console.WriteLine($"Description: {group.Description}");
        Console.WriteLine($"VpcId (if any): {group.VpcId}");
      }
    }


    //
    // Method to create a new security group (either EC2-Classic or EC2-VPC)
    // If vpcID is empty, the security group will be for EC2-Classic
    private static async Task<List<SecurityGroup>> CreateSecurityGroup(
      IAmazonEC2 ec2Client, string groupName, string vpcID)
    {
      // See if one or more security groups with that name
      // already exist in the given VPC. If so, return the list of them.
      var securityGroups = await FindSecurityGroups(ec2Client, groupName, vpcID);
      if (securityGroups.Count > 0)
      {
        Console.WriteLine(
          $"\nOne or more security groups with name {groupName} already exist.\n");
        return securityGroups;
      }

      // If the security group doesn't already exists, create it.
      var createRequest = new CreateSecurityGroupRequest{
        GroupName = groupName
      };
      if(string.IsNullOrEmpty(vpcID))
      {
        createRequest.Description = "Security group for .NET code example (no VPC specified)";
      }
      else
      {
        createRequest.VpcId = vpcID;
        createRequest.Description = "Security group for .NET code example (VPC: " + vpcID + ")";
      }
      CreateSecurityGroupResponse createResponse =
        await ec2Client.CreateSecurityGroupAsync(createRequest);

      // Return the new security group
      DescribeSecurityGroupsResponse describeResponse =
        await ec2Client.DescribeSecurityGroupsAsync(new DescribeSecurityGroupsRequest{
          GroupIds = new List<string>() { createResponse.GroupId }
        });
      return describeResponse.SecurityGroups;
    }


    //
    // Method to determine if a security group with the specified name
    // already exists in the VPC
    private static async Task<List<SecurityGroup>> FindSecurityGroups(
      IAmazonEC2 ec2Client, string groupName, string vpcID)
    {
      var request = new DescribeSecurityGroupsRequest();
      request.Filters.Add(new Filter{
        Name = "group-name",
        Values = new List<string>() { groupName }
      });
      if(!string.IsNullOrEmpty(vpcID))
        request.Filters.Add(new Filter{
          Name = "vpc-id",
          Values = new List<string>() { vpcID }
        });

      var response = await ec2Client.DescribeSecurityGroupsAsync(request);
      return response.SecurityGroups;
    }


    //
    // Command-line help
    private static void PrintHelp()
    {
      Console.WriteLine(
        "\nUsage: EC2CreateSecGroup -g <group-name> [-v <vpc-id>]" +
        "\n  -g, --group-name: The name you would like the new security group to have." +
        "\n  -v, --vpc-id: The ID of a VPC to which the new security group will belong." +
        "\n     If vpc-id isn't present, the security group will be" +
        "\n     for EC2-Classic (if your AWS account supports this)" +
        "\n     or will use the default VCP for EC2-VPC.");
    }
  }


  // = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
  // Class that represents a command line on the console or terminal.
  // (This is the same for all examples. When you have seen it once, you can ignore it.)
  static class CommandLine
  {
    //
    // Method to parse a command line of the form: "--key value" or "-k value".
    //
    // Parameters:
    // - args: The command-line arguments passed into the application by the system.
    //
    // Returns:
    // A Dictionary with string Keys and Values.
    //
    // If a key is found without a matching value, Dictionary.Value is set to the key
    //  (including the dashes).
    // If a value is found without a matching key, Dictionary.Key is set to "--NoKeyN",
    //  where "N" represents sequential numbers.
    public static Dictionary<string,string> Parse(string[] args)
    {
      var parsedArgs = new Dictionary<string,string>();
      int i = 0, n = 0;
      while(i < args.Length)
      {
        // If the first argument in this iteration starts with a dash it's an option.
        if(args[i].StartsWith("-"))
        {
          var key = args[i++];
          var value = key;

          // Check to see if there's a value that goes with this option?
          if((i < args.Length) && (!args[i].StartsWith("-"))) value = args[i++];
          parsedArgs.Add(key, value);
        }

        // If the first argument in this iteration doesn't start with a dash, it's a value
        else
        {
          parsedArgs.Add("--NoKey" + n.ToString(), args[i++]);
          n++;
        }
      }

      return parsedArgs;
    }

    //
    // Method to get an argument from the parsed command-line arguments
    //
    // Parameters:
    // - parsedArgs: The Dictionary object returned from the Parse() method (shown above).
    // - defaultValue: The default string to return if the specified key isn't in parsedArgs.
    // - keys: An array of keys to look for in parsedArgs.
    public static string GetArgument(
      Dictionary<string,string> parsedArgs, string defaultReturn, params string[] keys)
    {
      string retval = null;
      foreach(var key in keys)
        if(parsedArgs.TryGetValue(key, out retval)) break;
      return retval ?? defaultReturn;
    }

    //
    // Method to exit the application with an error.
    public static void ErrorExit(string msg, int code=1)
    {
      Console.WriteLine("\nError");
      Console.WriteLine(msg);
      Environment.Exit(code);
    }
  }

}
```

# 更新安全群組
<a name="authorize-ingress"></a>

此範例說明如何使用 適用於 .NET 的 AWS SDK 將規則新增至安全群組。特別是，此範例會新增規則，以允許特定 TCP 連接埠上的傳入流量，例如用於 EC2 執行個體的遠端連線。應用程式會取得現有安全群組的 ID、CIDR 格式的 IP 地址 （或地址範圍），以及選用的 TCP 連接埠號碼。然後，它會將傳入規則新增至指定的安全群組。

**注意**  
若要使用此範例，您需要 CIDR 格式的 IP 地址 （或地址範圍）。如需取得本機電腦 IP 地址的方法，請參閱本主題結尾**的其他考量**事項。

下列各節提供此範例的程式碼片段。之後會顯示[範例的完整程式碼](#authorize-ingress-complete-code)，並可依原樣建置和執行。

**Topics**
+ [

## 新增傳入規則
](#authorize-ingress-add-rule)
+ [

## 完成程式碼
](#authorize-ingress-complete-code)
+ [

## 其他考量
](#authorize-ingress-additional)

## 新增傳入規則
<a name="authorize-ingress-add-rule"></a>

下列程式碼片段會將傳入規則新增至特定 IP 地址 （或範圍） 和 TCP 連接埠的安全群組。

[本主題結尾](#authorize-ingress-complete-code)的範例顯示此程式碼片段正在使用中。

```
    //
    // Method that adds a TCP ingress rule to a security group
    private static async Task AddIngressRule(
      IAmazonEC2 eC2Client, string groupID, string ipAddress, int port)
    {
      // Create an object to hold the request information for the rule.
      // It uses an IpPermission object to hold the IP information for the rule.
      var ingressRequest = new AuthorizeSecurityGroupIngressRequest{
        GroupId = groupID};
      ingressRequest.IpPermissions.Add(new IpPermission{
        IpProtocol = "tcp",
        FromPort = port,
        ToPort = port,
        Ipv4Ranges = new List<IpRange>() { new IpRange { CidrIp = ipAddress } }
      });

      // Create the inbound rule for the security group
      AuthorizeSecurityGroupIngressResponse responseIngress =
        await eC2Client.AuthorizeSecurityGroupIngressAsync(ingressRequest);
      Console.WriteLine($"\nNew RDP rule was written in {groupID} for {ipAddress}.");
      Console.WriteLine($"Result: {responseIngress.HttpStatusCode}");
    }
```

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

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

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

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

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

  [AmazonEC2Client](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TEC2Client.html) 類別
+ 命名空間 [Amazon.EC2.Model](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/NEC2Model.html)

  類別 [AuthorizeSecurityGroupIngressRequest](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TAuthorizeSecurityGroupIngressRequest.html)

  類別 [AuthorizeSecurityGroupIngressResponse](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TAuthorizeSecurityGroupIngressResponse.html)

  類別 [IpPermission](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TIpPermission.html)

  類別 [IpRange](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TIpRange.html)

### 程式碼
<a name="w2aac19c15c17c13c17c17b7b1"></a>

```
using System;
using System.Threading.Tasks;
using System.Collections.Generic;
using Amazon.EC2;
using Amazon.EC2.Model;

namespace EC2AddRuleForRDP
{
  // = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
  // Class to add a rule that allows inbound traffic on TCP a port
  class Program
  {
    private const int DefaultPort = 3389;

    static async Task Main(string[] args)
    {
      // Parse the command line and show help if necessary
      var parsedArgs = CommandLine.Parse(args);
      if(parsedArgs.Count == 0)
      {
        PrintHelp();
        return;
      }

      // Get the application arguments from the parsed list
      var groupID = CommandLine.GetArgument(parsedArgs, null, "-g", "--group-id");
      var ipAddress = CommandLine.GetArgument(parsedArgs, null, "-i", "--ip-address");
      var portStr = CommandLine.GetArgument(parsedArgs, DefaultPort.ToString(), "-p", "--port");
      if(string.IsNullOrEmpty(ipAddress))
        CommandLine.ErrorExit("\nYou must supply an IP address in CIDR format.");
      if(string.IsNullOrEmpty(groupID) || !groupID.StartsWith("sg-"))
        CommandLine.ErrorExit("\nThe ID for a security group is missing or incorrect.");
      if(int.Parse(portStr) == 0)
        CommandLine.ErrorExit($"\nThe given TCP port number, {portStr}, isn't allowed.");

      // Add a rule to the given security group that allows
      // inbound traffic on a TCP port
      await AddIngressRule(
        new AmazonEC2Client(), groupID, ipAddress, int.Parse(portStr));
    }


    //
    // Method that adds a TCP ingress rule to a security group
    private static async Task AddIngressRule(
      IAmazonEC2 eC2Client, string groupID, string ipAddress, int port)
    {
      // Create an object to hold the request information for the rule.
      // It uses an IpPermission object to hold the IP information for the rule.
      var ingressRequest = new AuthorizeSecurityGroupIngressRequest{
        GroupId = groupID};
      ingressRequest.IpPermissions.Add(new IpPermission{
        IpProtocol = "tcp",
        FromPort = port,
        ToPort = port,
        Ipv4Ranges = new List<IpRange>() { new IpRange { CidrIp = ipAddress } }
      });

      // Create the inbound rule for the security group
      AuthorizeSecurityGroupIngressResponse responseIngress =
        await eC2Client.AuthorizeSecurityGroupIngressAsync(ingressRequest);
      Console.WriteLine($"\nNew RDP rule was written in {groupID} for {ipAddress}.");
      Console.WriteLine($"Result: {responseIngress.HttpStatusCode}");
    }


    //
    // Command-line help
    private static void PrintHelp()
    {
      Console.WriteLine(
        "\nUsage: EC2AddRuleForRDP -g <group-id> -i <ip-address> [-p <port>]" +
        "\n  -g, --group-id: The ID of the security group to which you want to add the inbound rule." +
        "\n  -i, --ip-address: An IP address or address range in CIDR format." +
        "\n  -p, --port: The TCP port number. Defaults to 3389.");
    }
  }


  // = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
  // Class that represents a command line on the console or terminal.
  // (This is the same for all examples. When you have seen it once, you can ignore it.)
  static class CommandLine
  {
    //
    // Method to parse a command line of the form: "--key value" or "-k value".
    //
    // Parameters:
    // - args: The command-line arguments passed into the application by the system.
    //
    // Returns:
    // A Dictionary with string Keys and Values.
    //
    // If a key is found without a matching value, Dictionary.Value is set to the key
    //  (including the dashes).
    // If a value is found without a matching key, Dictionary.Key is set to "--NoKeyN",
    //  where "N" represents sequential numbers.
    public static Dictionary<string,string> Parse(string[] args)
    {
      var parsedArgs = new Dictionary<string,string>();
      int i = 0, n = 0;
      while(i < args.Length)
      {
        // If the first argument in this iteration starts with a dash it's an option.
        if(args[i].StartsWith("-"))
        {
          var key = args[i++];
          var value = key;

          // Check to see if there's a value that goes with this option?
          if((i < args.Length) && (!args[i].StartsWith("-"))) value = args[i++];
          parsedArgs.Add(key, value);
        }

        // If the first argument in this iteration doesn't start with a dash, it's a value
        else
        {
          parsedArgs.Add("--NoKey" + n.ToString(), args[i++]);
          n++;
        }
      }

      return parsedArgs;
    }

    //
    // Method to get an argument from the parsed command-line arguments
    //
    // Parameters:
    // - parsedArgs: The Dictionary object returned from the Parse() method (shown above).
    // - defaultValue: The default string to return if the specified key isn't in parsedArgs.
    // - keys: An array of keys to look for in parsedArgs.
    public static string GetArgument(
      Dictionary<string,string> parsedArgs, string defaultReturn, params string[] keys)
    {
      string retval = null;
      foreach(var key in keys)
        if(parsedArgs.TryGetValue(key, out retval)) break;
      return retval ?? defaultReturn;
    }

    //
    // Method to exit the application with an error.
    public static void ErrorExit(string msg, int code=1)
    {
      Console.WriteLine("\nError");
      Console.WriteLine(msg);
      Environment.Exit(code);
    }
  }

}
```

## 其他考量
<a name="authorize-ingress-additional"></a>
+ 如果您未提供連接埠號碼，應用程式會預設為連接埠 3389。這是 Windows RDP 的連接埠，可讓您連線至執行 Windows 的 EC2 執行個體。如果您要啟動執行 Linux 的 EC2 執行個體，您可以改用 TCP 連接埠 22 (SSH)。
+ 請注意，範例`IpProtocol`設定為 "tcp"。您可以在 [IpPermission](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TIpPermission.html) 類別`IpProtocol`屬性的描述`IpProtocol`中找到 的值。
+ 當您使用此範例時，您可能想要本機電腦的 IP 地址。以下是您可以取得地址的一些方式。
  + 如果您的本機電腦 （您將從中連線到 EC2 執行個體） 具有靜態公有 IP 地址，您可以使用 服務來取得該地址。這類服務之一是 https：//[http://checkip.amazonaws.com/](http://checkip.amazonaws.com/)。若要進一步了解授權傳入流量，請參閱《[Amazon EC2 使用者指南](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/)》中的[將規則新增至安全群組](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/working-with-security-groups.html#adding-security-group-rule)和[不同使用案例的安全群組規則](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/security-group-rules-reference.html)。
  + 取得本機電腦 IP 地址的另一種方法是使用 [Amazon EC2 主控台](https://console.aws.amazon.com/ec2/v2/home#SecurityGroups)。

    選取其中一個安全群組，選取**傳入規則**索引標籤，然後選擇**編輯傳入規則**。在傳入規則中，開啟**來源**欄中的下拉式功能表，然後選擇**我的 IP**，以 CIDR 格式查看本機電腦的 IP 地址。請務必**取消**操作。
+ 您可以在 [Amazon EC2 主控台](https://console.aws.amazon.com/ec2/v2/home#SecurityGroups)中檢查安全群組清單，以驗證此範例的結果。

# 使用 Amazon EC2 金鑰對
<a name="key-pairs"></a>

Amazon EC2 使用公有金鑰加密法將登入資訊進行加密及解密。公有金鑰密碼編譯使用公有金鑰來加密資料，然後收件人使用私有金鑰來解密資料。公有金鑰和私有金鑰稱為金鑰對。如果您想要登入 EC2 執行個體，您必須在啟動時指定金鑰對，然後在連線時提供該對的私有金鑰。

當您啟動 EC2 執行個體時，您可以為其建立金鑰對，或使用您在啟動其他執行個體時已使用的金鑰對。若要進一步了解 Amazon EC2 金鑰對，請參閱《[Amazon EC2 使用者指南》中的使用 Amazon EC2 金鑰對](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-key-pairs.html)。 [Amazon EC2 ](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/)

如需 APIs和先決條件的相關資訊，請參閱父區段 ([使用 Amazon EC2](ec2-apis-intro.md))。

**Topics**
+ [

# 建立和顯示金鑰對
](create-save-key-pair.md)
+ [

# 刪除金鑰對
](delete-key-pairs.md)

# 建立和顯示金鑰對
<a name="create-save-key-pair"></a>

此範例說明如何使用 適用於 .NET 的 AWS SDK 來建立金鑰對。應用程式會取得新金鑰對的名稱和 PEM 檔案的名稱 （副檔名為 ".pem")。它會建立金鑰對、將私有金鑰寫入 PEM 檔案，然後顯示所有可用的金鑰對。如果您不提供命令列引數，應用程式只會顯示所有可用的金鑰對。

下列各節提供此範例的程式碼片段。之後會顯示[範例的完整程式碼](#create-save-key-pair-complete-code)，並可依原樣建置和執行。

**Topics**
+ [

## 建立金鑰對
](#create-save-key-pair-create)
+ [

## 顯示可用的金鑰對
](#create-save-key-pair-display)
+ [

## 完成程式碼
](#create-save-key-pair-complete-code)
+ [

## 其他考量
](#create-save-key-pair-additional)

## 建立金鑰對
<a name="create-save-key-pair-create"></a>

下列程式碼片段會建立金鑰對，然後將私有金鑰儲存到指定的 PEM 檔案。

[本主題結尾](#create-save-key-pair-complete-code)的範例顯示此程式碼片段正在使用中。

```
    //
    // Method to create a key pair and save the key material in a PEM file
    private static async Task CreateKeyPair(
      IAmazonEC2 ec2Client, string keyPairName, string pemFileName)
    {
      // Create the key pair
      CreateKeyPairResponse response =
        await ec2Client.CreateKeyPairAsync(new CreateKeyPairRequest{
          KeyName = keyPairName
        });
      Console.WriteLine($"\nCreated new key pair: {response.KeyPair.KeyName}");

      // Save the private key in a PEM file
      using (var s = new FileStream(pemFileName, FileMode.Create))
      using (var writer = new StreamWriter(s))
      {
        writer.WriteLine(response.KeyPair.KeyMaterial);
      }
    }
```

## 顯示可用的金鑰對
<a name="create-save-key-pair-display"></a>

下列程式碼片段會顯示可用金鑰對的清單。

[本主題結尾](#create-save-key-pair-complete-code)的範例顯示此程式碼片段正在使用中。

```
    //
    // Method to show the key pairs that are available
    private static async Task EnumerateKeyPairs(IAmazonEC2 ec2Client)
    {
      DescribeKeyPairsResponse response = await ec2Client.DescribeKeyPairsAsync();
      Console.WriteLine("Available key pairs:");
      foreach (KeyPairInfo item in response.KeyPairs)
        Console.WriteLine($"  {item.KeyName}");
    }
```

## 完成程式碼
<a name="create-save-key-pair-complete-code"></a>

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

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

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

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

  [AmazonEC2Client](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TEC2Client.html) 類別
+ 命名空間 [Amazon.EC2.Model](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/NEC2Model.html)

  類別 [CreateKeyPairRequest](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TCreateKeyPairRequest.html)

  類別 [CreateKeyPairResponse](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TCreateKeyPairResponse.html)

  類別 [DescribeKeyPairsResponse](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TDescribeKeyPairsResponse.html)

  類別 [KeyPairInfo](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TKeyPairInfo.html)

### 程式碼
<a name="w2aac19c15c17c15c11c19b7b1"></a>

```
using System;
using System.Threading.Tasks;
using System.IO;
using Amazon.EC2;
using Amazon.EC2.Model;
using System.Collections.Generic;

namespace EC2CreateKeyPair
{
  // = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
  // Class to create and store a key pair
  class Program
  {
    static async Task Main(string[] args)
    {
      // Create the EC2 client
      var ec2Client = new AmazonEC2Client();

      // Parse the command line and show help if necessary
      var parsedArgs = CommandLine.Parse(args);
      if(parsedArgs.Count == 0)
      {
        // In the case of no command-line arguments,
        // just show help and the existing key pairs
        PrintHelp();
        Console.WriteLine("\nNo arguments specified.");
        Console.Write(
          "Do you want to see a list of the existing key pairs? ((y) or n): ");
        string response = Console.ReadLine();
        if((string.IsNullOrEmpty(response)) || (response.ToLower() == "y"))
          await EnumerateKeyPairs(ec2Client);
        return;
      }

      // Get the application arguments from the parsed list
      string keyPairName =
        CommandLine.GetArgument(parsedArgs, null, "-k", "--keypair-name");
      string pemFileName =
        CommandLine.GetArgument(parsedArgs, null, "-p", "--pem-filename");
      if(string.IsNullOrEmpty(keyPairName))
        CommandLine.ErrorExit("\nNo key pair name specified." +
          "\nRun the command with no arguments to see help.");
      if(string.IsNullOrEmpty(pemFileName) || !pemFileName.EndsWith(".pem"))
        CommandLine.ErrorExit("\nThe PEM filename is missing or incorrect." +
          "\nRun the command with no arguments to see help.");

      // Create the key pair
      await CreateKeyPair(ec2Client, keyPairName, pemFileName);
      await EnumerateKeyPairs(ec2Client);
    }


    //
    // Method to create a key pair and save the key material in a PEM file
    private static async Task CreateKeyPair(
      IAmazonEC2 ec2Client, string keyPairName, string pemFileName)
    {
      // Create the key pair
      CreateKeyPairResponse response =
        await ec2Client.CreateKeyPairAsync(new CreateKeyPairRequest{
          KeyName = keyPairName
        });
      Console.WriteLine($"\nCreated new key pair: {response.KeyPair.KeyName}");

      // Save the private key in a PEM file
      using (var s = new FileStream(pemFileName, FileMode.Create))
      using (var writer = new StreamWriter(s))
      {
        writer.WriteLine(response.KeyPair.KeyMaterial);
      }
    }


    //
    // Method to show the key pairs that are available
    private static async Task EnumerateKeyPairs(IAmazonEC2 ec2Client)
    {
      DescribeKeyPairsResponse response = await ec2Client.DescribeKeyPairsAsync();
      Console.WriteLine("Available key pairs:");
      foreach (KeyPairInfo item in response.KeyPairs)
        Console.WriteLine($"  {item.KeyName}");
    }


    //
    // Command-line help
    private static void PrintHelp()
    {
      Console.WriteLine(
        "\nUsage: EC2CreateKeyPair -k <keypair-name> -p <pem-filename>" +
        "\n  -k, --keypair-name: The name you want to assign to the key pair." +
        "\n  -p, --pem-filename: The name of the PEM file to create, with a \".pem\" extension.");
    }
  }


  // = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
  // Class that represents a command line on the console or terminal.
  // (This is the same for all examples. When you have seen it once, you can ignore it.)
  static class CommandLine
  {
    //
    // Method to parse a command line of the form: "--key value" or "-k value".
    //
    // Parameters:
    // - args: The command-line arguments passed into the application by the system.
    //
    // Returns:
    // A Dictionary with string Keys and Values.
    //
    // If a key is found without a matching value, Dictionary.Value is set to the key
    //  (including the dashes).
    // If a value is found without a matching key, Dictionary.Key is set to "--NoKeyN",
    //  where "N" represents sequential numbers.
    public static Dictionary<string,string> Parse(string[] args)
    {
      var parsedArgs = new Dictionary<string,string>();
      int i = 0, n = 0;
      while(i < args.Length)
      {
        // If the first argument in this iteration starts with a dash it's an option.
        if(args[i].StartsWith("-"))
        {
          var key = args[i++];
          var value = key;

          // Check to see if there's a value that goes with this option?
          if((i < args.Length) && (!args[i].StartsWith("-"))) value = args[i++];
          parsedArgs.Add(key, value);
        }

        // If the first argument in this iteration doesn't start with a dash, it's a value
        else
        {
          parsedArgs.Add("--NoKey" + n.ToString(), args[i++]);
          n++;
        }
      }

      return parsedArgs;
    }

    //
    // Method to get an argument from the parsed command-line arguments
    //
    // Parameters:
    // - parsedArgs: The Dictionary object returned from the Parse() method (shown above).
    // - defaultValue: The default string to return if the specified key isn't in parsedArgs.
    // - keys: An array of keys to look for in parsedArgs.
    public static string GetArgument(
      Dictionary<string,string> parsedArgs, string defaultReturn, params string[] keys)
    {
      string retval = null;
      foreach(var key in keys)
        if(parsedArgs.TryGetValue(key, out retval)) break;
      return retval ?? defaultReturn;
    }

    //
    // Method to exit the application with an error.
    public static void ErrorExit(string msg, int code=1)
    {
      Console.WriteLine("\nError");
      Console.WriteLine(msg);
      Environment.Exit(code);
    }
  }

}
```

## 其他考量
<a name="create-save-key-pair-additional"></a>
+ 執行範例後，您可以在 [Amazon EC2 主控台](https://console.aws.amazon.com/ec2/#KeyPairs)中看到新的金鑰對。
+ 建立金鑰對時，您必須儲存傳回的私有金鑰，因為您稍後無法擷取私有金鑰。

# 刪除金鑰對
<a name="delete-key-pairs"></a>

此範例說明如何使用 適用於 .NET 的 AWS SDK 刪除金鑰對。應用程式會取得金鑰對的名稱。它會刪除金鑰對，然後顯示所有可用的金鑰對。如果您不提供命令列引數，應用程式只會顯示所有可用的金鑰對。

下列各節提供此範例的程式碼片段。之後會顯示[範例的完整程式碼](#delete-key-pairs-complete-code)，並可依原樣建置和執行。

**Topics**
+ [

## 刪除金鑰對
](#delete-key-pairs-create)
+ [

## 顯示可用的金鑰對
](#delete-key-pairs-display)
+ [

## 完成程式碼
](#delete-key-pairs-complete-code)

## 刪除金鑰對
<a name="delete-key-pairs-create"></a>

下列程式碼片段會刪除金鑰對。

[本主題結尾](#delete-key-pairs-complete-code)的範例顯示此程式碼片段正在使用中。

```
    //
    // Method to delete a key pair
    private static async Task DeleteKeyPair(IAmazonEC2 ec2Client, string keyName)
    {
      await ec2Client.DeleteKeyPairAsync(new DeleteKeyPairRequest{
        KeyName = keyName});
      Console.WriteLine($"\nKey pair {keyName} has been deleted (if it existed).");
    }
```

## 顯示可用的金鑰對
<a name="delete-key-pairs-display"></a>

下列程式碼片段會顯示可用金鑰對的清單。

[本主題結尾](#delete-key-pairs-complete-code)的範例顯示此程式碼片段正在使用中。

```
    //
    // Method to show the key pairs that are available
    private static async Task EnumerateKeyPairs(IAmazonEC2 ec2Client)
    {
      DescribeKeyPairsResponse response = await ec2Client.DescribeKeyPairsAsync();
      Console.WriteLine("Available key pairs:");
      foreach (KeyPairInfo item in response.KeyPairs)
        Console.WriteLine($"  {item.KeyName}");
    }
```

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

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

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

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

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

  [AmazonEC2Client](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TEC2Client.html) 類別
+ 命名空間 [Amazon.EC2.Model](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/NEC2Model.html)

  類別 [https://docs.aws.amazon.com/sdkfornet/v3/apidocs/](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/)

  類別 [DescribeKeyPairsResponse](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TDescribeKeyPairsResponse.html)

  類別 [KeyPairInfo](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TKeyPairInfo.html)

### 程式碼
<a name="w2aac19c15c17c15c13c19b7b1"></a>

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

namespace EC2DeleteKeyPair
{
  class Program
  {
    static async Task Main(string[] args)
    {
      // Create the EC2 client
      var ec2Client = new AmazonEC2Client();

      if(args.Length == 1)
      {
        // Delete a key pair (if it exists)
        await DeleteKeyPair(ec2Client, args[0]);

        // Display the key pairs that are left
        await EnumerateKeyPairs(ec2Client);
      }
      else
      {
        Console.WriteLine("\nUsage: EC2DeleteKeyPair keypair-name");
        Console.WriteLine("  keypair-name - The name of the key pair you want to delete.");
        Console.WriteLine("\nNo arguments specified.");
        Console.Write(
          "Do you want to see a list of the existing key pairs? ((y) or n): ");
        string response = Console.ReadLine();
        if((string.IsNullOrEmpty(response)) || (response.ToLower() == "y"))
          await EnumerateKeyPairs(ec2Client);
      }
    }


    //
    // Method to delete a key pair
    private static async Task DeleteKeyPair(IAmazonEC2 ec2Client, string keyName)
    {
      await ec2Client.DeleteKeyPairAsync(new DeleteKeyPairRequest{
        KeyName = keyName});
      Console.WriteLine($"\nKey pair {keyName} has been deleted (if it existed).");
    }


    //
    // Method to show the key pairs that are available
    private static async Task EnumerateKeyPairs(IAmazonEC2 ec2Client)
    {
      DescribeKeyPairsResponse response = await ec2Client.DescribeKeyPairsAsync();
      Console.WriteLine("Available key pairs:");
      foreach (KeyPairInfo item in response.KeyPairs)
        Console.WriteLine($"  {item.KeyName}");
    }
  }
}
```

# 查看您的 Amazon EC2 區域和可用區域
<a name="using-regions-and-availability-zones"></a>

Amazon EC2 託管於全球多個位置。這些地點是由 區域及可用區域組成。每個區域都是獨立的地理區域，具有多個隔離的位置，稱為可用區域。

若要進一步了解區域和可用區域，請參閱《[Amazon EC2 使用者指南](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/)》中的[區域和區域](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-regions-availability-zones.html)。

此範例說明如何使用 適用於 .NET 的 AWS SDK 來取得與 EC2 用戶端相關的區域和可用區域的詳細資訊。應用程式會顯示 EC2 用戶端可用的區域和可用區域的清單。

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

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

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

  [AmazonEC2Client](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TEC2Client.html) 類別
+ 命名空間 [Amazon.EC2.Model](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/NEC2Model.html)

  類別 [DescribeAvailabilityZonesResponse](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TDescribeAvailabilityZonesResponse.html)

  類別 [DescribeRegionsResponse](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TDescribeRegionsResponse.html)

  類別[AvailabilityZone](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TAvailabilityZone.html)

  類別[區域](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TRegion.html)

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

namespace EC2RegionsAndZones
{
  class Program
  {
    static async Task Main(string[] args)
    {
      Console.WriteLine(
        "Finding the Regions and Availability Zones available to an EC2 client...");

      // Create the EC2 client
      var ec2Client = new AmazonEC2Client();

      // Display the Regions and Availability Zones
      await DescribeRegions(ec2Client);
      await DescribeAvailabilityZones(ec2Client);
    }


    //
    // Method to display Regions
    private static async Task DescribeRegions(IAmazonEC2 ec2Client)
    {
      Console.WriteLine("\nRegions that are enabled for the EC2 client:");
      DescribeRegionsResponse response = await ec2Client.DescribeRegionsAsync();
      foreach (Region region in response.Regions)
        Console.WriteLine(region.RegionName);
    }


    //
    // Method to display Availability Zones
    private static async Task DescribeAvailabilityZones(IAmazonEC2 ec2Client)
    {
      Console.WriteLine("\nAvailability Zones for the EC2 client's region:");
      DescribeAvailabilityZonesResponse response =
        await ec2Client.DescribeAvailabilityZonesAsync();
      foreach (AvailabilityZone az in response.AvailabilityZones)
        Console.WriteLine(az.ZoneName);
    }
  }
}
```

# 使用 Amazon EC2 執行個體
<a name="how-to-ec2"></a>

您可以使用 透過建立、啟動和終止等操作 適用於 .NET 的 AWS SDK 來控制 Amazon EC2 執行個體。本節中的主題提供一些如何執行此操作的範例。若要進一步了解 EC2 執行個體，請參閱《[Amazon EC2 使用者指南》中的 Amazon EC2 執行個體](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/Instances.html)。 [Amazon EC2 ](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/)

如需 APIs和先決條件的相關資訊，請參閱父區段 ([使用 Amazon EC2](ec2-apis-intro.md))。

**Topics**
+ [啟動 EC2 執行個體](run-instance.md)
+ [終止 EC2 執行個體](terminate-instance.md)

# 啟動 Amazon EC2 執行個體
<a name="run-instance"></a>

此範例說明如何使用 適用於 .NET 的 AWS SDK ，從相同的 Amazon Machine Image (AMI) 啟動一或多個設定相同的 Amazon EC2 執行個體。使用您提供的[數個輸入](#run-instance-gather)，應用程式會啟動 EC2 執行個體，然後監控執行個體，直到其處於「待定」狀態為止。

當 EC2 執行個體執行時，您可以遠端連線到它，如中所述[（選用） 連線至執行個體](#connect-to-instance)。

**警告**  
EC2-Classic 在 2022 年 8 月 15 日淘汰。建議您從 EC2-Classic 遷移至 VPC。如需詳細資訊，請參閱部落格文章 [EC2-Classic Networking 正在淘汰 – 以下是如何準備](https://aws.amazon.com/blogs/aws/ec2-classic-is-retiring-heres-how-to-prepare/)。

下列各節提供此範例的程式碼片段和其他資訊。[範例的完整程式碼](#run-instance-complete-code)會顯示在程式碼片段之後，並可依原樣建置和執行。

**Topics**
+ [

## 收集您需要的內容
](#run-instance-gather)
+ [

## 啟動執行個體
](#run-instance-launch)
+ [

## 監控執行個體
](#run-instance-monitor)
+ [

## 完成程式碼
](#run-instance-complete-code)
+ [

## 其他考量
](#run-instance-additional)
+ [

## （選用） 連線至執行個體
](#connect-to-instance)
+ [

## 清除
](#run-instance-cleanup)

## 收集您需要的內容
<a name="run-instance-gather"></a>

若要啟動 EC2 執行個體，您需要幾件事。
+ 將啟動執行個體的 [VPC](https://docs.aws.amazon.com/vpc/latest/userguide/)。如果它是 Windows 執行個體，而且您將透過 RDP 連接到它，VPC 很可能需要連接網際網路閘道，以及路由表中網際網路閘道的項目。如需詳細資訊，請參閱《Amazon VPC 使用者指南》**中的[網際網路閘道](https://docs.aws.amazon.com/vpc/latest/userguide/VPC_Internet_Gateway.html)。
+ 要啟動執行個體之 VPC 中現有子網路的 ID。尋找或建立此項目的簡單方法是登入 [Amazon VPC 主控台](https://console.aws.amazon.com/vpc/home#subnets)，但您也可以使用 [CreateSubnetAsync](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/MEC2CreateSubnetAsyncCreateSubnetRequestCancellationToken.html) 和 [DescribeSubnetsAsync](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/MEC2DescribeSubnetsAsyncDescribeSubnetsRequestCancellationToken.html) 方法，以程式設計方式取得。
**注意**  
如果您未提供此參數，新的執行個體會在您帳戶的預設 VPC 中啟動。
+ 屬於要啟動執行個體之 VPC 的現有安全群組 ID。如需詳細資訊，請參閱[在 Amazon EC2 中使用安全群組](security-groups.md)。
+ 如果您想要連線到新的執行個體，先前提及的安全群組必須具有適當的傳入規則，允許連接埠 22 (Linux 執行個體） 上的 SSH 流量或連接埠 3389 (Windows 執行個體） 上的 RDP 流量。如需如何執行此操作的詳細資訊，請參閱 [更新安全群組](authorize-ingress.md)，包括該主題[其他考量](authorize-ingress.md#authorize-ingress-additional)接近結尾的 。
+ 將用於建立執行個體的 Amazon Machine Image (AMI)。如需 AMIs的相關資訊，請參閱《[Amazon EC2 使用者指南》中的 Amazon Machine Image (AMIs)](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/AMIs.html)。 [Amazon EC2 ](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/) 特別是，請參閱[尋找 AMI](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/finding-an-ami.html) 和[共用 AMIs](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/sharing-amis.html)。
+ 現有 EC2 金鑰對的名稱，用於連線至新執行個體。如需詳細資訊，請參閱[使用 Amazon EC2 金鑰對](key-pairs.md)。
+ 包含先前提及之 EC2 金鑰對私有金鑰的 PEM 檔案名稱。當您[從遠端連線至](#connect-to-instance)執行個體時，會使用 PEM 檔案。

## 啟動執行個體
<a name="run-instance-launch"></a>

下列程式碼片段會啟動 EC2 執行個體。

本[主題結尾附近](#run-instance-complete-code)的範例顯示此程式碼片段的使用中。

```
    //
    // Method to launch the instances
    // Returns a list with the launched instance IDs
    private static async Task<List<string>> LaunchInstances(
      IAmazonEC2 ec2Client, RunInstancesRequest requestLaunch)
    {
      var instanceIds = new List<string>();
      RunInstancesResponse responseLaunch =
        await ec2Client.RunInstancesAsync(requestLaunch);

      Console.WriteLine("\nNew instances have been created.");
      foreach (Instance item in responseLaunch.Reservation.Instances)
      {
        instanceIds.Add(item.InstanceId);
        Console.WriteLine($"  New instance: {item.InstanceId}");
      }

      return instanceIds;
    }
```

## 監控執行個體
<a name="run-instance-monitor"></a>

下列程式碼片段會監控執行個體，直到其處於「待定」狀態為止。

本[主題結尾附近](#run-instance-complete-code)的範例顯示此程式碼片段正在使用中。

如需 `Instance.State.Code` 屬性的有效值，請參閱 [InstanceState](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TInstanceState.html) 類別。

```
    //
    // Method to wait until the instances are running (or at least not pending)
    private static async Task CheckState(IAmazonEC2 ec2Client, List<string> instanceIds)
    {
      Console.WriteLine(
        "\nWaiting for the instances to start." +
        "\nPress any key to stop waiting. (Response might be slightly delayed.)");

      int numberRunning;
      DescribeInstancesResponse responseDescribe;
      var requestDescribe = new DescribeInstancesRequest{
        InstanceIds = instanceIds};

      // Check every couple of seconds
      int wait = 2000;
      while(true)
      {
        // Get and check the status for each of the instances to see if it's past pending.
        // Once all instances are past pending, break out.
        // (For this example, we are assuming that there is only one reservation.)
        Console.Write(".");
        numberRunning = 0;
        responseDescribe = await ec2Client.DescribeInstancesAsync(requestDescribe);
        foreach(Instance i in responseDescribe.Reservations[0].Instances)
        {
          // Check the lower byte of State.Code property
          // Code == 0 is the pending state
          if((i.State.Code & 255) > 0) numberRunning++;
        }
        if(numberRunning == responseDescribe.Reservations[0].Instances.Count)
          break;

        // Wait a bit and try again (unless the user wants to stop waiting)
        Thread.Sleep(wait);
        if(Console.KeyAvailable)
          break;
      }

      Console.WriteLine("\nNo more instances are pending.");
      foreach(Instance i in responseDescribe.Reservations[0].Instances)
      {
        Console.WriteLine($"For {i.InstanceId}:");
        Console.WriteLine($"  VPC ID: {i.VpcId}");
        Console.WriteLine($"  Instance state: {i.State.Name}");
        Console.WriteLine($"  Public IP address: {i.PublicIpAddress}");
        Console.WriteLine($"  Public DNS name: {i.PublicDnsName}");
        Console.WriteLine($"  Key pair name: {i.KeyName}");
      }
    }
```

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

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

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

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

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

  [AmazonEC2Client](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TEC2Client.html) 類別

  類別 [InstanceType](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TInstanceType.html)
+ 命名空間 [Amazon.EC2.Model](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/NEC2Model.html)

  類別 [DescribeInstancesRequest](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TDescribeInstancesRequest.html)

  類別 [DescribeInstancesResponse](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TDescribeInstancesResponse.html)

  類別[執行個體](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TInstance.html)

  類別 [InstanceNetworkInterfaceSpecification](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TInstanceNetworkInterfaceSpecification.html)

  類別 [RunInstancesRequest](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TRunInstancesRequest.html)

  類別 [RunInstancesResponse](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TRunInstancesResponse.html)

### 程式碼
<a name="w2aac19c15c17c19b9c27b7b1"></a>

```
using System;
using System.Threading;
using System.Threading.Tasks;
using System.Collections.Generic;
using Amazon.EC2;
using Amazon.EC2.Model;

namespace EC2LaunchInstance
{
  // = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
  // Class to launch an EC2 instance
  class Program
  {
    static async Task Main(string[] args)
    {
      // Parse the command line and show help if necessary
      var parsedArgs = CommandLine.Parse(args);
      if(parsedArgs.Count == 0)
      {
        PrintHelp();
        return;
      }

      // Get the application arguments from the parsed list
      string groupID =
        CommandLine.GetArgument(parsedArgs, null, "-g", "--group-id");
      string ami =
        CommandLine.GetArgument(parsedArgs, null, "-a", "--ami-id");
      string keyPairName =
        CommandLine.GetArgument(parsedArgs, null, "-k", "--keypair-name");
      string subnetID =
        CommandLine.GetArgument(parsedArgs, null, "-s", "--subnet-id");
      if(   (string.IsNullOrEmpty(groupID) || !groupID.StartsWith("sg-"))
         || (string.IsNullOrEmpty(ami) || !ami.StartsWith("ami-"))
         || (string.IsNullOrEmpty(keyPairName))
         || (!string.IsNullOrEmpty(subnetID) && !subnetID.StartsWith("subnet-")))
        CommandLine.ErrorExit(
          "\nOne or more of the required arguments is missing or incorrect." +
          "\nRun the command with no arguments to see help.");

      // Create an EC2 client
      var ec2Client = new AmazonEC2Client();

      // Create an object with the necessary properties
      RunInstancesRequest request = GetRequestData(groupID, ami, keyPairName, subnetID);

      // Launch the instances and wait for them to start running
      var instanceIds = await LaunchInstances(ec2Client, request);
      await CheckState(ec2Client, instanceIds);
    }


    //
    // Method to put together the properties needed to launch the instance.
    private static RunInstancesRequest GetRequestData(
      string groupID, string ami, string keyPairName, string subnetID)
    {
      // Common properties
      var groupIDs = new List<string>() { groupID };
      var request = new RunInstancesRequest()
      {
        // The first three of these would be additional command-line arguments or similar.
        InstanceType = InstanceType.T1Micro,
        MinCount = 1,
        MaxCount = 1,
        ImageId = ami,
        KeyName = keyPairName
      };

      // Properties specifically for EC2 in a VPC.
      if(!string.IsNullOrEmpty(subnetID))
      {
        request.NetworkInterfaces =
          new List<InstanceNetworkInterfaceSpecification>() {
            new InstanceNetworkInterfaceSpecification() {
              DeviceIndex = 0,
              SubnetId = subnetID,
              Groups = groupIDs,
              AssociatePublicIpAddress = true
            }
          };
      }

      // Properties specifically for EC2-Classic
      else
      {
        request.SecurityGroupIds = groupIDs;
      }
      return request;
    }


    //
    // Method to launch the instances
    // Returns a list with the launched instance IDs
    private static async Task<List<string>> LaunchInstances(
      IAmazonEC2 ec2Client, RunInstancesRequest requestLaunch)
    {
      var instanceIds = new List<string>();
      RunInstancesResponse responseLaunch =
        await ec2Client.RunInstancesAsync(requestLaunch);

      Console.WriteLine("\nNew instances have been created.");
      foreach (Instance item in responseLaunch.Reservation.Instances)
      {
        instanceIds.Add(item.InstanceId);
        Console.WriteLine($"  New instance: {item.InstanceId}");
      }

      return instanceIds;
    }


    //
    // Method to wait until the instances are running (or at least not pending)
    private static async Task CheckState(IAmazonEC2 ec2Client, List<string> instanceIds)
    {
      Console.WriteLine(
        "\nWaiting for the instances to start." +
        "\nPress any key to stop waiting. (Response might be slightly delayed.)");

      int numberRunning;
      DescribeInstancesResponse responseDescribe;
      var requestDescribe = new DescribeInstancesRequest{
        InstanceIds = instanceIds};

      // Check every couple of seconds
      int wait = 2000;
      while(true)
      {
        // Get and check the status for each of the instances to see if it's past pending.
        // Once all instances are past pending, break out.
        // (For this example, we are assuming that there is only one reservation.)
        Console.Write(".");
        numberRunning = 0;
        responseDescribe = await ec2Client.DescribeInstancesAsync(requestDescribe);
        foreach(Instance i in responseDescribe.Reservations[0].Instances)
        {
          // Check the lower byte of State.Code property
          // Code == 0 is the pending state
          if((i.State.Code & 255) > 0) numberRunning++;
        }
        if(numberRunning == responseDescribe.Reservations[0].Instances.Count)
          break;

        // Wait a bit and try again (unless the user wants to stop waiting)
        Thread.Sleep(wait);
        if(Console.KeyAvailable)
          break;
      }

      Console.WriteLine("\nNo more instances are pending.");
      foreach(Instance i in responseDescribe.Reservations[0].Instances)
      {
        Console.WriteLine($"For {i.InstanceId}:");
        Console.WriteLine($"  VPC ID: {i.VpcId}");
        Console.WriteLine($"  Instance state: {i.State.Name}");
        Console.WriteLine($"  Public IP address: {i.PublicIpAddress}");
        Console.WriteLine($"  Public DNS name: {i.PublicDnsName}");
        Console.WriteLine($"  Key pair name: {i.KeyName}");
      }
    }


    //
    // Command-line help
    private static void PrintHelp()
    {
      Console.WriteLine(
        "\nUsage: EC2LaunchInstance -g <group-id> -a <ami-id> -k <keypair-name> [-s <subnet-id>]" +
        "\n  -g, --group-id: The ID of the security group." +
        "\n  -a, --ami-id: The ID of an Amazon Machine Image." +
        "\n  -k, --keypair-name - The name of a key pair." +
        "\n  -s, --subnet-id: The ID of a subnet. Required only for EC2 in a VPC.");
    }
  }


  // = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
  // Class that represents a command line on the console or terminal.
  // (This is the same for all examples. When you have seen it once, you can ignore it.)
  static class CommandLine
  {
    //
    // Method to parse a command line of the form: "--key value" or "-k value".
    //
    // Parameters:
    // - args: The command-line arguments passed into the application by the system.
    //
    // Returns:
    // A Dictionary with string Keys and Values.
    //
    // If a key is found without a matching value, Dictionary.Value is set to the key
    //  (including the dashes).
    // If a value is found without a matching key, Dictionary.Key is set to "--NoKeyN",
    //  where "N" represents sequential numbers.
    public static Dictionary<string,string> Parse(string[] args)
    {
      var parsedArgs = new Dictionary<string,string>();
      int i = 0, n = 0;
      while(i < args.Length)
      {
        // If the first argument in this iteration starts with a dash it's an option.
        if(args[i].StartsWith("-"))
        {
          var key = args[i++];
          var value = key;

          // Check to see if there's a value that goes with this option?
          if((i < args.Length) && (!args[i].StartsWith("-"))) value = args[i++];
          parsedArgs.Add(key, value);
        }

        // If the first argument in this iteration doesn't start with a dash, it's a value
        else
        {
          parsedArgs.Add("--NoKey" + n.ToString(), args[i++]);
          n++;
        }
      }

      return parsedArgs;
    }

    //
    // Method to get an argument from the parsed command-line arguments
    //
    // Parameters:
    // - parsedArgs: The Dictionary object returned from the Parse() method (shown above).
    // - defaultValue: The default string to return if the specified key isn't in parsedArgs.
    // - keys: An array of keys to look for in parsedArgs.
    public static string GetArgument(
      Dictionary<string,string> parsedArgs, string defaultReturn, params string[] keys)
    {
      string retval = null;
      foreach(var key in keys)
        if(parsedArgs.TryGetValue(key, out retval)) break;
      return retval ?? defaultReturn;
    }

    //
    // Method to exit the application with an error.
    public static void ErrorExit(string msg, int code=1)
    {
      Console.WriteLine("\nError");
      Console.WriteLine(msg);
      Environment.Exit(code);
    }
  }

}
```

## 其他考量
<a name="run-instance-additional"></a>
+ 檢查 EC2 執行個體的狀態時，您可以將篩選條件新增至 [DescribeInstancesRequest](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TDescribeInstancesRequest.html) 物件的 `Filter` 屬性。使用此技術，您可以將請求限制為特定執行個體，例如具有特定使用者指定標籤的執行個體。
+ 為了簡潔起見，某些屬性被給予典型值。任何或所有這些屬性都可以透過程式設計方式或使用者輸入來決定。
+ 您可以用於 [RunInstancesRequest](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TRunInstancesRequest.html) 物件的 `MinCount`和 `MaxCount` 屬性的值取決於目標可用區域，以及執行個體類型允許的執行個體數量上限。如需詳細資訊，請參閱 [Amazon EC2 一般常見問答集中的我可以在 Amazon EC2 中執行多少執行個體](https://aws.amazon.com/ec2/faqs/#How_many_instances_can_I_run_in_Amazon_EC2)。 Amazon EC2 
+ 如果您想要使用與此範例不同的執行個體類型，有數種執行個體類型可供選擇。如需詳細資訊，請參閱[《Amazon EC2 使用者指南》中的 Amazon EC2 執行個體類型](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instance-types.html)。 [Amazon EC2 ](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/) 另請參閱[執行個體類型詳細資訊](https://aws.amazon.com/ec2/instance-types/)和[執行個體類型總](https://aws.amazon.com/ec2/instance-explorer/)管。
+ 您也可以在啟動執行個體時，將 [IAM 角色](net-dg-hosm.md)連接至執行個體。若要這樣做，請建立`Name`屬性設定為 IAM 角色名稱的 [IamInstanceProfileSpecification](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TIamInstanceProfileSpecification.html) 物件。然後將該物件新增至 [RunInstancesRequest](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TRunInstancesRequest.html) 物件的 `IamInstanceProfile` 屬性。
**注意**  
若要啟動已連接 IAM 角色的 EC2 執行個體，IAM 使用者的組態必須包含特定許可。如需所需許可的詳細資訊，請參閱《[Amazon EC2 使用者指南](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/)》中的[授予使用者將 IAM 角色傳遞至執行個體的許可](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/iam-roles-for-amazon-ec2.html#permission-to-pass-iam-roles)。

## （選用） 連線至執行個體
<a name="connect-to-instance"></a>

執行個體執行後，您可以使用適當的遠端用戶端從遠端連線到它。對於 Linux 和 Windows 執行個體，您需要執行個體的公有 IP 地址或公有 DNS 名稱。您也需要下列項目。

**針對 Linux 執行個體**

您可以使用 SSH 用戶端連線到您的 Linux 執行個體。請確定您在啟動執行個體時使用的安全群組允許連接埠 22 上的 SSH 流量，如中所述[更新安全群組](authorize-ingress.md)。

您也需要用來啟動執行個體之金鑰對的私有部分，也就是 PEM 檔案。

如需詳細資訊，請參閱《Amazon EC2 使用者指南》中的[連線至 Linux 執行個體](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/connect-to-linux-instance.html)。

**對於 Windows 執行個體**

您可以使用 RDP 用戶端連線到執行個體。請確定您在啟動執行個體時使用的安全群組允許連接埠 3389 上的 RDP 流量，如中所述[更新安全群組](authorize-ingress.md)。

您也需要管理員密碼。您可以使用下列範例程式碼來取得此程式碼，該程式碼需要執行個體 ID 和用來啟動執行個體之金鑰對的私有部分，也就是 PEM 檔案。

如需詳細資訊，請參閱《Amazon EC2 使用者指南》中的[連線至 Windows 執行個體](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/connecting_to_windows_instance.html)。

**警告**  
此範例程式碼會傳回執行個體的純文字管理員密碼。

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

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

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

  [AmazonEC2Client](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TEC2Client.html) 類別
+ 命名空間 [Amazon.EC2.Model](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/NEC2Model.html)

  類別 [GetPasswordDataRequest](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TGetPasswordDataRequest.html)

  類別 [GetPasswordDataResponse](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TGetPasswordDataResponse.html)

### 程式碼
<a name="w2aac19c15c17c19b9c35c25b1"></a>

```
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using Amazon.EC2;
using Amazon.EC2.Model;

namespace EC2GetWindowsPassword
{
  // = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
  // Class to get the Administrator password of a Windows EC2 instance
  class Program
  {
    static async Task Main(string[] args)
    {
      // Parse the command line and show help if necessary
      var parsedArgs = CommandLine.Parse(args);
      if(parsedArgs.Count == 0)
      {
        PrintHelp();
        return;
      }

      // Get the application arguments from the parsed list
      string instanceID =
        CommandLine.GetArgument(parsedArgs, null, "-i", "--instance-id");
      string pemFileName =
        CommandLine.GetArgument(parsedArgs, null, "-p", "--pem-filename");
      if(   (string.IsNullOrEmpty(instanceID) || !instanceID.StartsWith("i-"))
         || (string.IsNullOrEmpty(pemFileName) || !pemFileName.EndsWith(".pem")))
        CommandLine.ErrorExit(
          "\nOne or more of the required arguments is missing or incorrect." +
          "\nRun the command with no arguments to see help.");

      // Create the EC2 client
      var ec2Client = new AmazonEC2Client();

      // Get and display the password
      string password = await GetPassword(ec2Client, instanceID, pemFileName);
      Console.WriteLine($"\nPassword: {password}");
    }


    //
    // Method to get the administrator password of a Windows EC2 instance
    private static async Task<string> GetPassword(
      IAmazonEC2 ec2Client, string instanceID, string pemFilename)
    {
      string password = string.Empty;
      GetPasswordDataResponse response =
        await ec2Client.GetPasswordDataAsync(new GetPasswordDataRequest{
          InstanceId = instanceID});
      if(response.PasswordData != null)
      {
        password = response.GetDecryptedPassword(File.ReadAllText(pemFilename));
      }
      else
      {
        Console.WriteLine($"\nThe password is not available for instance {instanceID}.");
        Console.WriteLine($"If this is a Windows instance, the password might not be ready.");
      }
      return password;
    }


    //
    // Command-line help
    private static void PrintHelp()
    {
      Console.WriteLine(
        "\nUsage: EC2GetWindowsPassword -i <instance-id> -p pem-filename" +
        "\n  -i, --instance-id: The name of the EC2 instance." +
        "\n  -p, --pem-filename: The name of the PEM file with the private key.");
    }
  }

  // = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
  // Class that represents a command line on the console or terminal.
  // (This is the same for all examples. When you have seen it once, you can ignore it.)
  static class CommandLine
  {
    //
    // Method to parse a command line of the form: "--key value" or "-k value".
    //
    // Parameters:
    // - args: The command-line arguments passed into the application by the system.
    //
    // Returns:
    // A Dictionary with string Keys and Values.
    //
    // If a key is found without a matching value, Dictionary.Value is set to the key
    //  (including the dashes).
    // If a value is found without a matching key, Dictionary.Key is set to "--NoKeyN",
    //  where "N" represents sequential numbers.
    public static Dictionary<string,string> Parse(string[] args)
    {
      var parsedArgs = new Dictionary<string,string>();
      int i = 0, n = 0;
      while(i < args.Length)
      {
        // If the first argument in this iteration starts with a dash it's an option.
        if(args[i].StartsWith("-"))
        {
          var key = args[i++];
          var value = key;

          // Check to see if there's a value that goes with this option?
          if((i < args.Length) && (!args[i].StartsWith("-"))) value = args[i++];
          parsedArgs.Add(key, value);
        }

        // If the first argument in this iteration doesn't start with a dash, it's a value
        else
        {
          parsedArgs.Add("--NoKey" + n.ToString(), args[i++]);
          n++;
        }
      }

      return parsedArgs;
    }

    //
    // Method to get an argument from the parsed command-line arguments
    //
    // Parameters:
    // - parsedArgs: The Dictionary object returned from the Parse() method (shown above).
    // - defaultValue: The default string to return if the specified key isn't in parsedArgs.
    // - keys: An array of keys to look for in parsedArgs.
    public static string GetArgument(
      Dictionary<string,string> parsedArgs, string defaultReturn, params string[] keys)
    {
      string retval = null;
      foreach(var key in keys)
        if(parsedArgs.TryGetValue(key, out retval)) break;
      return retval ?? defaultReturn;
    }

    //
    // Method to exit the application with an error.
    public static void ErrorExit(string msg, int code=1)
    {
      Console.WriteLine("\nError");
      Console.WriteLine(msg);
      Environment.Exit(code);
    }
  }

}
```

## 清除
<a name="run-instance-cleanup"></a>

當您不再需要 EC2 執行個體時，請務必將其終止，如中所述[終止 Amazon EC2 執行個體](terminate-instance.md)。

# 終止 Amazon EC2 執行個體
<a name="terminate-instance"></a>

當您不再需要一或多個 Amazon EC2 執行個體時，您可以終止它們。

此範例說明如何使用 適用於 .NET 的 AWS SDK 來終止 EC2 執行個體。它需要執行個體 ID 做為輸入。

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

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

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

  [AmazonEC2Client](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TEC2Client.html) 類別
+ 命名空間 [Amazon.EC2.Model](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/NEC2Model.html)

  類別 [TerminateInstancesRequest](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TTerminateInstancesRequest.html)

  類別 [TerminateInstancesResponse](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TTerminateInstancesResponse.html)

```
using System;
using System.Threading.Tasks;
using System.Collections.Generic;
using Amazon.EC2;
using Amazon.EC2.Model;

namespace EC2TerminateInstance
{
  class Program
  {
    static async Task Main(string[] args)
    {
      if((args.Length == 1) && (args[0].StartsWith("i-")))
      {
        // Terminate the instance
        var ec2Client = new AmazonEC2Client();
        await TerminateInstance(ec2Client, args[0]);
      }
      else
      {
        Console.WriteLine("\nCommand-line argument missing or incorrect.");
        Console.WriteLine("\nUsage: EC2TerminateInstance instance-ID");
        Console.WriteLine("  instance-ID - The EC2 instance you want to terminate.");
        return;
      }
    }

    //
    // Method to terminate an EC2 instance
    private static async Task TerminateInstance(IAmazonEC2 ec2Client, string instanceID)
    {
      var request = new TerminateInstancesRequest{
        InstanceIds = new List<string>() { instanceID }};
      TerminateInstancesResponse response =
        await ec2Client.TerminateInstancesAsync(new TerminateInstancesRequest{
          InstanceIds = new List<string>() { instanceID }
        });
      foreach (InstanceStateChange item in response.TerminatingInstances)
      {
        Console.WriteLine("Terminated instance: " + item.InstanceId);
        Console.WriteLine("Instance state: " + item.CurrentState.Name);
      }
    }
  }
}
```

執行範例之後，最好登入 [Amazon EC2 主控台](https://console.aws.amazon.com/ec2/)，以確認 [EC2 執行個體](https://console.aws.amazon.com/ec2/v2/home#Instances)已終止。

# Amazon EC2 Spot 執行個體教學課程
<a name="how-to-spot-instances"></a>

本教學課程說明如何使用 適用於 .NET 的 AWS SDK 來管理 Amazon EC2 Spot 執行個體。

## 概觀
<a name="tutor-spot-net-overview"></a>

Spot 執行個體可讓您以低於隨需價格的價格請求未使用的 Amazon EC2 容量。這可以大幅降低可中斷之應用程式的 EC2 成本。

以下是 Spot 執行個體的請求和使用方式的高階摘要。

1. 建立 Spot 執行個體請求，指定您願意支付的最高價格。

1. 完成請求後，像執行任何其他 Amazon EC2 執行個體一樣執行執行個體。

1. 視需要執行執行個體，然後終止執行個體，除非 *Spot 價格*變更，讓執行個體為您終止。

1. 當您不再需要 Spot 執行個體請求時，請將其清除，以便不再建立 Spot 執行個體。

這是 Spot 執行個體的非常高階概觀。若要進一步了解 Spot 執行個體，請參閱《[Amazon EC2 使用者指南](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/)》中的 [Spot 執行個體](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-spot-instances.html)。

## 關於本教學
<a name="about-spot-instances-tutorial"></a>

當您遵循本教學課程時，您可以使用 適用於 .NET 的 AWS SDK 執行下列動作：
+ 建立 Spot 執行個體請求
+ 判斷 Spot 執行個體請求何時完成
+ 取消 Spot 執行個體請求
+ 終止關聯的執行個體

下列各節提供此範例的程式碼片段和其他資訊。[範例的完整程式碼](#tutor-spot-net-main)會顯示在程式碼片段之後，並可依原樣建置和執行。

**Topics**
+ [

## 概觀
](#tutor-spot-net-overview)
+ [

## 關於本教學
](#about-spot-instances-tutorial)
+ [

## 先決條件
](#tutor-spot-net-prereq)
+ [

## 收集您需要的內容
](#tutor-spot-net-gather)
+ [

## 建立 Spot 執行個體請求
](#tutor-spot-net-submit)
+ [

## 判斷 Spot 執行個體請求的狀態
](#tutor-spot-net-request-state)
+ [

## 清除 Spot 執行個體請求
](#tutor-spot-net-clean-up-request)
+ [

## 清除 Spot 執行個體
](#tutor-spot-net-clean-up-instance)
+ [

## 完成程式碼
](#tutor-spot-net-main)
+ [

## 其他考量
](#tutor-spot-net-additional)

## 先決條件
<a name="tutor-spot-net-prereq"></a>

如需 APIs和先決條件的相關資訊，請參閱父區段 ([使用 Amazon EC2](ec2-apis-intro.md))。

## 收集您需要的內容
<a name="tutor-spot-net-gather"></a>

若要建立 Spot 執行個體請求，您需要幾件事。
+ 執行個體數量及其執行個體類型。有數種執行個體類型可供選擇。如需詳細資訊，請參閱[《Amazon EC2 使用者指南》中的 Amazon EC2 執行個體類型](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instance-types.html)。 [Amazon EC2 ](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/) 另請參閱[執行個體類型詳細資訊](https://aws.amazon.com/ec2/instance-types/)和[執行個體類型總](https://aws.amazon.com/ec2/instance-explorer/)管。

  此教學課程的預設編號為 1。
+ 用來建立執行個體的 Amazon Machine Image (AMI)。如需 AMIs的相關資訊，請參閱《[Amazon EC2 使用者指南》中的 Amazon Machine Image (AMIs)](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/AMIs.html)。 [Amazon EC2 ](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/) 特別是，請參閱[尋找 AMI](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/finding-an-ami.html) 和[共用 AMIs](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/sharing-amis.html)。
+ 您願意為每個執行個體小時支付的最高價格。您可以在 [Amazon EC2 定價頁面上](https://aws.amazon.com/ec2/pricing/)查看所有執行個體類型 （適用於隨需執行個體和 Spot 執行個體） 的價格。本教學課程的預設價格將於稍後說明。
+ 如果您想要從遠端連線至執行個體，則為具有適當組態和資源的安全群組。這在 中說明，[在 Amazon EC2 中使用安全群組](security-groups.md)以及[收集您需要的內容](run-instance.md#run-instance-gather)並[連接到 中執行個體](run-instance.md#connect-to-instance)的相關資訊[啟動 Amazon EC2 執行個體](run-instance.md)。為求簡化，本教學課程使用****所有較新 AWS 帳戶預設的安全群組。

請求 Spot 執行個體的方法有很多種。以下是常見的策略：
+ 提出一定低於隨需定價的請求。
+ 根據產生的運算值提出請求。
+ 提出請求以盡快取得運算容量。

下列說明參考《[Amazon EC2 使用者指南](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/)》中的 [Spot 執行個體定價歷史記錄](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-spot-instances-history.html)。

### 將成本降低到低於隨需
<a name="reduce-cost"></a>

您可以批次處理任務，需要花費數小時或數天的時間完成。但是，在開始和結束時都有彈性。您想要查看是否能以低於隨需執行個體的成本將它完成。

您可以使用 Amazon EC2 主控台或 Amazon EC2 API 來檢查執行個體類型的 Spot 價格歷史記錄。於一個給定的可用區域內分析您所想要的執行個體類型的歷史價格後，您的出價有兩個替代方式：
+ 在 Spot 價格範圍的上端指定請求，該請求仍低於隨需價格，預期您的一次性 Spot 執行個體請求最有可能實現並執行足夠的連續運算時間來完成任務。
+ 或者，您可以出價此 Spot 價格範圍的下限，並計畫如何透過一個持久性的請求來結合數個已長期啟動的執行個體。該執行個體將總共要執行一段夠長時間，才能以更低的成本完成任務。

### 支付不超過結果值的費用
<a name="value-of-result"></a>

您有一個要執行的資料正在處理任務。您充分了解任務結果的值，以得知其在運算成本方面的價值。

分析執行個體類型的 Spot 價格歷史記錄後，您可以選擇運算時間成本不超過任務結果值的價格。您建立可以長久出價的方式，且允許它在 Spot 價格出現波動並等於或低於您的出價時，間歇性地執行。

### 快速取得運算容量
<a name="acquire-quickly"></a>

對於無法透過隨需執行個體取得的額外容量，您有非預期的短期需求。分析執行個體類型的 Spot 價格歷史記錄後，您可以選擇高於最高歷史價格的價格，以大幅提高快速完成請求的可能性，並繼續運算，直到完成為止。

在您收集所需的內容並選擇策略之後，您就可以請求 Spot 執行個體。在本教學課程中，預設最大 Spot 執行個體價格設定為與隨需價格相同 (在本教學課程中為 \$10.003 美元)。以這種方法設定價格能夠最大化實現請求的機會。

## 建立 Spot 執行個體請求
<a name="tutor-spot-net-submit"></a>

下列程式碼片段說明如何使用先前收集的元素建立 Spot 執行個體請求。

[本主題結尾](#tutor-spot-net-main)的範例顯示此程式碼片段正在使用中。

```
    //
    // Method to create a Spot Instance request
    private static async Task<SpotInstanceRequest> CreateSpotInstanceRequest(
      IAmazonEC2 ec2Client, string amiId, string securityGroupName,
      InstanceType instanceType, string spotPrice, int instanceCount)
    {
      var launchSpecification = new LaunchSpecification{
        ImageId = amiId,
        InstanceType = instanceType
      };
      launchSpecification.SecurityGroups.Add(securityGroupName);
      var request = new RequestSpotInstancesRequest{
        SpotPrice = spotPrice,
        InstanceCount = instanceCount,
        LaunchSpecification = launchSpecification
      };

      RequestSpotInstancesResponse result =
        await ec2Client.RequestSpotInstancesAsync(request);
      return result.SpotInstanceRequests[0];
    }
```

從此方法傳回的重要值是 Spot 執行個體請求 ID，其中包含在傳回的 [SpotInstanceRequest](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TSpotInstanceRequest.html) 物件`SpotInstanceRequestId`成員中。

**注意**  
您將需要為啟動的任何 Spot 執行個體支付費用。為了避免不必要的成本，請務必[取消任何請求](#tutor-spot-net-clean-up-request)並[終止任何執行個體](#tutor-spot-net-clean-up-instance)。

## 判斷 Spot 執行個體請求的狀態
<a name="tutor-spot-net-request-state"></a>

下列程式碼片段說明如何取得 Spot 執行個體請求的相關資訊。您可以使用該資訊在程式碼中做出特定決策，例如是否繼續等待 Spot 執行個體請求履行。

[本主題結尾](#tutor-spot-net-main)的範例顯示此程式碼片段正在使用中。

```
    //
    // Method to get information about a Spot Instance request, including the status,
    // instance ID, etc.
    // It gets the information for a specific request (as opposed to all requests).
    private static async Task<SpotInstanceRequest> GetSpotInstanceRequestInfo(
      IAmazonEC2 ec2Client, string requestId)
    {
      var describeRequest = new DescribeSpotInstanceRequestsRequest();
      describeRequest.SpotInstanceRequestIds.Add(requestId);

      DescribeSpotInstanceRequestsResponse describeResponse =
        await ec2Client.DescribeSpotInstanceRequestsAsync(describeRequest);
      return describeResponse.SpotInstanceRequests[0];
    }
```

方法會傳回 Spot 執行個體請求的相關資訊，例如執行個體 ID、其狀態和狀態碼。如需 Spot 執行個體請求狀態碼的詳細資訊，請參閱《[Amazon EC2 使用者指南》中的](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/) [Spot 請求狀態](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/spot-bid-status.html#spot-instance-bid-status-understand)。

## 清除 Spot 執行個體請求
<a name="tutor-spot-net-clean-up-request"></a>

當您不再需要請求 Spot 執行個體時，請務必取消任何未完成的請求，以防止這些請求重新履行。下列程式碼片段說明如何取消 Spot 執行個體請求。

[本主題結尾](#tutor-spot-net-main)的範例顯示此程式碼片段正在使用中。

```
    //
    // Method to cancel a Spot Instance request
    private static async Task CancelSpotInstanceRequest(
      IAmazonEC2 ec2Client, string requestId)
    {
      var cancelRequest = new CancelSpotInstanceRequestsRequest();
      cancelRequest.SpotInstanceRequestIds.Add(requestId);

      await ec2Client.CancelSpotInstanceRequestsAsync(cancelRequest);
    }
```

## 清除 Spot 執行個體
<a name="tutor-spot-net-clean-up-instance"></a>

為了避免不必要的成本，請務必終止從 Spot 執行個體請求啟動的任何執行個體；只要取消 Spot 執行個體請求就不會終止您的執行個體，這表示您將繼續支付這些執行個體的費用。下列程式碼片段示範如何在取得作用中 Spot 執行個體的執行個體識別符後終止執行個體。

[本主題結尾](#tutor-spot-net-main)的範例顯示此程式碼片段正在使用中。

```
    //
    // Method to terminate a Spot Instance
    private static async Task TerminateSpotInstance(
      IAmazonEC2 ec2Client, string requestId)
    {
      var describeRequest = new DescribeSpotInstanceRequestsRequest();
      describeRequest.SpotInstanceRequestIds.Add(requestId);

      // Retrieve the Spot Instance request to check for running instances.
      DescribeSpotInstanceRequestsResponse describeResponse =
        await ec2Client.DescribeSpotInstanceRequestsAsync(describeRequest);

      // If there are any running instances, terminate them
      if(   (describeResponse.SpotInstanceRequests[0].Status.Code
              == "request-canceled-and-instance-running")
         || (describeResponse.SpotInstanceRequests[0].State == SpotInstanceState.Active))
      {
        TerminateInstancesResponse response =
          await ec2Client.TerminateInstancesAsync(new TerminateInstancesRequest{
            InstanceIds = new List<string>(){
              describeResponse.SpotInstanceRequests[0].InstanceId } });
        foreach (InstanceStateChange item in response.TerminatingInstances)
        {
          Console.WriteLine($"\n  Terminated instance: {item.InstanceId}");
          Console.WriteLine($"  Instance state: {item.CurrentState.Name}\n");
        }
      }
    }
```

## 完成程式碼
<a name="tutor-spot-net-main"></a>

下列程式碼範例會呼叫先前所述的方法來建立和取消 Spot 執行個體請求，並終止 Spot 執行個體。

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

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

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

  [AmazonEC2Client](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TEC2Client.html) 類別

  類別 [InstanceType](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TInstanceType.html)
+ 命名空間 [Amazon.EC2.Model](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/NEC2Model.html)

  類別 [CancelSpotInstanceRequestsRequest](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TCancelSpotInstanceRequestsRequest.html)

  類別 [DescribeSpotInstanceRequestsRequest](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TDescribeSpotInstanceRequestsRequest.html)

  類別 [DescribeSpotInstanceRequestsResponse](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TDescribeSpotInstanceRequestsResponse.html)

  類別 [InstanceStateChange](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TInstanceStateChange.html)

  類別 [LaunchSpecification](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TLaunchSpecification.html)

  Class [RequestSpotInstancesRequest](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TRequestSpotInstancesRequest.html)

  Class [RequestSpotInstancesResponse](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TRequestSpotInstancesResponse.html)

  類別 [SpotInstanceRequest](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TSpotInstanceRequest.html)

  類別 [TerminateInstancesRequest](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TTerminateInstancesRequest.html)

  類別 [TerminateInstancesResponse](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/EC2/TTerminateInstancesResponse.html)

### 程式碼
<a name="w2aac19c15c17c21c43b7b1"></a>

```
using System;
using System.Threading;
using System.Threading.Tasks;
using System.Collections.Generic;
using Amazon.EC2;
using Amazon.EC2.Model;

namespace EC2SpotInstanceRequests
{
  class Program
  {
    static async Task Main(string[] args)
    {
      // Some default values.
      // These could be made into command-line arguments instead.
      var instanceType = InstanceType.T1Micro;
      string securityGroupName = "default";
      string spotPrice = "0.003";
      int instanceCount = 1;

      // Parse the command line arguments
      if((args.Length != 1) || (!args[0].StartsWith("ami-")))
      {
        Console.WriteLine("\nUsage: EC2SpotInstanceRequests ami");
        Console.WriteLine("  ami: the Amazon Machine Image to use for the Spot Instances.");
        return;
      }

      // Create the Amazon EC2 client.
      var ec2Client = new AmazonEC2Client();

      // Create the Spot Instance request and record its ID
      Console.WriteLine("\nCreating spot instance request...");
      var req = await CreateSpotInstanceRequest(
        ec2Client, args[0], securityGroupName, instanceType, spotPrice, instanceCount);
      string requestId = req.SpotInstanceRequestId;

      // Wait for an EC2 Spot Instance to become active
      Console.WriteLine(
        $"Waiting for Spot Instance request with ID {requestId} to become active...");
      int wait = 1;
      var start = DateTime.Now;
      while(true)
      {
        Console.Write(".");

        // Get and check the status to see if the request has been fulfilled.
        var requestInfo = await GetSpotInstanceRequestInfo(ec2Client, requestId);
        if(requestInfo.Status.Code == "fulfilled")
        {
          Console.WriteLine($"\nSpot Instance request {requestId} " +
            $"has been fulfilled by instance {requestInfo.InstanceId}.\n");
          break;
        }

        // Wait a bit and try again, longer each time (1, 2, 4, ...)
        Thread.Sleep(wait);
        wait = wait * 2;
      }

      // Show the user how long it took to fulfill the Spot Instance request.
      TimeSpan span = DateTime.Now.Subtract(start);
      Console.WriteLine($"That took {span.TotalMilliseconds} milliseconds");

      // Perform actions here as needed.
      // For this example, simply wait for the user to hit a key.
      // That gives them a chance to look at the EC2 console to see
      // the running instance if they want to.
      Console.WriteLine("Press any key to start the cleanup...");
      Console.ReadKey(true);

      // Cancel the request.
      // Do this first to make sure that the request can't be re-fulfilled
      // once the Spot Instance has been terminated.
      Console.WriteLine("Canceling Spot Instance request...");
      await CancelSpotInstanceRequest(ec2Client, requestId);

      // Terminate the Spot Instance that's running.
      Console.WriteLine("Terminating the running Spot Instance...");
      await TerminateSpotInstance(ec2Client, requestId);

      Console.WriteLine("Done. Press any key to exit...");
      Console.ReadKey(true);
    }


    //
    // Method to create a Spot Instance request
    private static async Task<SpotInstanceRequest> CreateSpotInstanceRequest(
      IAmazonEC2 ec2Client, string amiId, string securityGroupName,
      InstanceType instanceType, string spotPrice, int instanceCount)
    {
      var launchSpecification = new LaunchSpecification{
        ImageId = amiId,
        InstanceType = instanceType
      };
      launchSpecification.SecurityGroups.Add(securityGroupName);
      var request = new RequestSpotInstancesRequest{
        SpotPrice = spotPrice,
        InstanceCount = instanceCount,
        LaunchSpecification = launchSpecification
      };

      RequestSpotInstancesResponse result =
        await ec2Client.RequestSpotInstancesAsync(request);
      return result.SpotInstanceRequests[0];
    }


    //
    // Method to get information about a Spot Instance request, including the status,
    // instance ID, etc.
    // It gets the information for a specific request (as opposed to all requests).
    private static async Task<SpotInstanceRequest> GetSpotInstanceRequestInfo(
      IAmazonEC2 ec2Client, string requestId)
    {
      var describeRequest = new DescribeSpotInstanceRequestsRequest();
      describeRequest.SpotInstanceRequestIds.Add(requestId);

      DescribeSpotInstanceRequestsResponse describeResponse =
        await ec2Client.DescribeSpotInstanceRequestsAsync(describeRequest);
      return describeResponse.SpotInstanceRequests[0];
    }


    //
    // Method to cancel a Spot Instance request
    private static async Task CancelSpotInstanceRequest(
      IAmazonEC2 ec2Client, string requestId)
    {
      var cancelRequest = new CancelSpotInstanceRequestsRequest();
      cancelRequest.SpotInstanceRequestIds.Add(requestId);

      await ec2Client.CancelSpotInstanceRequestsAsync(cancelRequest);
    }


    //
    // Method to terminate a Spot Instance
    private static async Task TerminateSpotInstance(
      IAmazonEC2 ec2Client, string requestId)
    {
      var describeRequest = new DescribeSpotInstanceRequestsRequest();
      describeRequest.SpotInstanceRequestIds.Add(requestId);

      // Retrieve the Spot Instance request to check for running instances.
      DescribeSpotInstanceRequestsResponse describeResponse =
        await ec2Client.DescribeSpotInstanceRequestsAsync(describeRequest);

      // If there are any running instances, terminate them
      if(   (describeResponse.SpotInstanceRequests[0].Status.Code
              == "request-canceled-and-instance-running")
         || (describeResponse.SpotInstanceRequests[0].State == SpotInstanceState.Active))
      {
        TerminateInstancesResponse response =
          await ec2Client.TerminateInstancesAsync(new TerminateInstancesRequest{
            InstanceIds = new List<string>(){
              describeResponse.SpotInstanceRequests[0].InstanceId } });
        foreach (InstanceStateChange item in response.TerminatingInstances)
        {
          Console.WriteLine($"\n  Terminated instance: {item.InstanceId}");
          Console.WriteLine($"  Instance state: {item.CurrentState.Name}\n");
        }
      }
    }
  }
}
```

## 其他考量
<a name="tutor-spot-net-additional"></a>
+ 執行教學課程後，最好登入 [Amazon EC2 主控台](https://console.aws.amazon.com/ec2/)，確認 [Spot 執行個體請求](https://console.aws.amazon.com/ec2/home#SpotInstances:)已取消，且 [Spot 執行個體](https://console.aws.amazon.com/ec2/v2/home#Instances)已終止。

# 使用 存取 AWS Identity and Access Management (IAM) 適用於 .NET 的 AWS SDK
<a name="iam-apis-intro"></a>

 適用於 .NET 的 AWS SDK 支援 [AWS Identity and Access Management](https://docs.aws.amazon.com/IAM/latest/UserGuide/)，這是一種 Web 服務，可讓 AWS 客戶管理 中的使用者和使用者許可 AWS。

 AWS Identity and Access Management (IAM) *使用者*是您建立的實體 AWS。實體代表與 互動的人員或應用程式 AWS。如需 IAM 使用者的詳細資訊，請參閱《IAM 使用者指南》中的 IAM [使用者](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_users.html)和 IAM [和 STS 限制](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_iam-limits.html)。

您可以透過建立 IAM *政策*將許可授予使用者。政策包含*政策文件*，其中列出使用者可以執行的動作，以及這些動作可以影響的資源。如需 IAM 政策的詳細資訊，請參閱《*IAM 使用者指南*[》中的政策和許可](https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html)。

**警告**  
為避免安全風險，在開發專用軟體或使用真實資料時，請勿使用 IAM 使用者進行身分驗證。相反地，搭配使用聯合功能和身分提供者，例如 [AWS IAM Identity Center](https://docs.aws.amazon.com/singlesignon/latest/userguide/what-is.html)。

## API
<a name="w2aac19c15c19c13"></a>

為 IAM 用戶端 適用於 .NET 的 AWS SDK 提供 APIs。APIs 可讓您使用 IAM 功能，例如使用者、角色和存取金鑰。

本節包含一些範例，顯示您在使用這些 APIs 時可遵循的模式。若要檢視完整的 APIs，請參閱 [適用於 .NET 的 AWS SDK API 參考](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/) （並捲動至「Amazon.IdentityManagement」)。

本節也包含[範例](net-dg-hosm.md)，說明如何將 IAM 角色連接至 Amazon EC2 執行個體，以便更輕鬆地管理登入資料。

IAM APIs 由 [AWSSDK.IdentityManagement](https://www.nuget.org/packages/AWSSDK.IdentityManagement) NuGet 套件提供。

## 先決條件
<a name="w2aac19c15c19c15"></a>

開始之前，請確定您已[設定環境和專案](net-dg-config.md)。也請檢閱 中的資訊[開發套件功能](net-dg-sdk-features.md)。

## 主題
<a name="w2aac19c15c19c17"></a>

**Topics**
+ [

## API
](#w2aac19c15c19c13)
+ [

## 先決條件
](#w2aac19c15c19c15)
+ [

## 主題
](#w2aac19c15c19c17)
+ [從 JSON 建立受管政策](iam-policies-create-json.md)
+ [顯示政策文件](iam-policies-display.md)
+ [使用角色授予存取權](net-dg-hosm.md)

# 從 JSON 建立 IAM 受管政策
<a name="iam-policies-create-json"></a>

此範例說明如何使用 從 JSON 中的指定政策文件中 適用於 .NET 的 AWS SDK 建立 [IAM 受](https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_managed-vs-inline.html#aws-managed-policies)管政策。應用程式會建立 IAM 用戶端物件、從 檔案讀取政策文件，然後建立政策。

**注意**  
如需 JSON 中的範例政策文件，請參閱本主題結尾[的其他考量](#iam-policies-create-json-additional)事項。

下列各節提供此範例的程式碼片段。之後會顯示[範例的完整程式碼](#iam-policies-create-json-complete-code)，並可依原樣建置和執行。

**Topics**
+ [

## 建立政策
](#iam-policies-create-json-create)
+ [

## 完成程式碼
](#iam-policies-create-json-complete-code)
+ [

## 其他考量
](#iam-policies-create-json-additional)

## 建立政策
<a name="iam-policies-create-json-create"></a>

下列程式碼片段會建立具有指定名稱和政策文件的 IAM 受管政策。

[本主題結尾](#iam-policies-create-json-complete-code)的範例顯示此程式碼片段正在使用中。

```
    //
    // Method to create an IAM policy from a JSON file
    private static async Task<CreatePolicyResponse> CreateManagedPolicy(
      IAmazonIdentityManagementService iamClient, string policyName, string jsonFilename)
    {
      return await iamClient.CreatePolicyAsync(new CreatePolicyRequest{
        PolicyName = policyName,
        PolicyDocument = File.ReadAllText(jsonFilename)});
    }
```

## 完成程式碼
<a name="iam-policies-create-json-complete-code"></a>

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

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

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

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

  [AmazonIdentityManagementServiceClient](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/IAM/TIAMServiceClient.html) 類別
+ 命名空間 [Amazon.IdentityManagement.Model](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/IAM/NIAMModel.html)

  類別 [CreatePolicyRequest](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/IAM/TCreatePolicyRequest.html)

  類別 [CreatePolicyResponse](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/IAM/TCreatePolicyResponse.html)

### 程式碼
<a name="w2aac19c15c19c21c17b7b1"></a>

```
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using Amazon.IdentityManagement;
using Amazon.IdentityManagement.Model;

namespace IamCreatePolicyFromJson
{
  // = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
  // Class to create an IAM policy with a given policy document
  class Program
  {
    private const int MaxArgs = 2;

    static async Task Main(string[] args)
    {
      // Parse the command line and show help if necessary
      var parsedArgs = CommandLine.Parse(args);
      if((parsedArgs.Count == 0) || (parsedArgs.Count > MaxArgs))
      {
        PrintHelp();
        return;
      }

      // Get the application arguments from the parsed list
      string policyName =
        CommandLine.GetArgument(parsedArgs, null, "-p", "--policy-name");
      string policyFilename =
        CommandLine.GetArgument(parsedArgs, null, "-j", "--json-filename");
      if(   string.IsNullOrEmpty(policyName)
         || (string.IsNullOrEmpty(policyFilename) || !policyFilename.EndsWith(".json")))
        CommandLine.ErrorExit(
          "\nOne or more of the required arguments is missing or incorrect." +
          "\nRun the command with no arguments to see help.");

      // Create an IAM service client
      var iamClient = new AmazonIdentityManagementServiceClient();

      // Create the new policy
      var response = await CreateManagedPolicy(iamClient, policyName, policyFilename);
      Console.WriteLine($"\nPolicy {response.Policy.PolicyName} has been created.");
      Console.WriteLine($"  Arn: {response.Policy.Arn}");
    }


    //
    // Method to create an IAM policy from a JSON file
    private static async Task<CreatePolicyResponse> CreateManagedPolicy(
      IAmazonIdentityManagementService iamClient, string policyName, string jsonFilename)
    {
      return await iamClient.CreatePolicyAsync(new CreatePolicyRequest{
        PolicyName = policyName,
        PolicyDocument = File.ReadAllText(jsonFilename)});
    }


    //
    // Command-line help
    private static void PrintHelp()
    {
      Console.WriteLine(
        "\nUsage: IamCreatePolicyFromJson -p <policy-name> -j <json-filename>" +
        "\n  -p, --policy-name: The name you want the new policy to have." +
        "\n  -j, --json-filename: The name of the JSON file with the policy document.");
    }
  }


  // = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
  // Class that represents a command line on the console or terminal.
  // (This is the same for all examples. When you have seen it once, you can ignore it.)
  static class CommandLine
  {
    //
    // Method to parse a command line of the form: "--key value" or "-k value".
    //
    // Parameters:
    // - args: The command-line arguments passed into the application by the system.
    //
    // Returns:
    // A Dictionary with string Keys and Values.
    //
    // If a key is found without a matching value, Dictionary.Value is set to the key
    //  (including the dashes).
    // If a value is found without a matching key, Dictionary.Key is set to "--NoKeyN",
    //  where "N" represents sequential numbers.
    public static Dictionary<string,string> Parse(string[] args)
    {
      var parsedArgs = new Dictionary<string,string>();
      int i = 0, n = 0;
      while(i < args.Length)
      {
        // If the first argument in this iteration starts with a dash it's an option.
        if(args[i].StartsWith("-"))
        {
          var key = args[i++];
          var value = key;

          // Check to see if there's a value that goes with this option?
          if((i < args.Length) && (!args[i].StartsWith("-"))) value = args[i++];
          parsedArgs.Add(key, value);
        }

        // If the first argument in this iteration doesn't start with a dash, it's a value
        else
        {
          parsedArgs.Add("--NoKey" + n.ToString(), args[i++]);
          n++;
        }
      }

      return parsedArgs;
    }

    //
    // Method to get an argument from the parsed command-line arguments
    //
    // Parameters:
    // - parsedArgs: The Dictionary object returned from the Parse() method (shown above).
    // - defaultValue: The default string to return if the specified key isn't in parsedArgs.
    // - keys: An array of keys to look for in parsedArgs.
    public static string GetArgument(
      Dictionary<string,string> parsedArgs, string defaultReturn, params string[] keys)
    {
      string retval = null;
      foreach(var key in keys)
        if(parsedArgs.TryGetValue(key, out retval)) break;
      return retval ?? defaultReturn;
    }

    //
    // Method to exit the application with an error.
    public static void ErrorExit(string msg, int code=1)
    {
      Console.WriteLine("\nError");
      Console.WriteLine(msg);
      Environment.Exit(code);
    }
  }

}
```

## 其他考量
<a name="iam-policies-create-json-additional"></a>
+ 以下是您可以複製到 JSON 檔案並用作此應用程式輸入的範例政策文件：

------
#### [ JSON ]

****  

  ```
  {
    "Version":"2012-10-17",		 	 	 
    "Id"  : "DotnetTutorialPolicy",
    "Statement" : [
      {
        "Sid" : "DotnetTutorialPolicyS3",
        "Effect" : "Allow",
        "Action" : [
          "s3:Get*",
          "s3:List*"
        ],
        "Resource" : "*"
      },
      {
        "Sid" : "DotnetTutorialPolicyPolly",
        "Effect": "Allow",
        "Action": [
          "polly:DescribeVoices",
          "polly:SynthesizeSpeech"
        ],
        "Resource": "*"
      }
    ]
  }
  ```

------
+ 您可以在 [IAM 主控台](https://console.aws.amazon.com/iam/home#/policies)中查看政策是否已建立。在**篩選政策**下拉式清單中，選取**客戶受管**。當您不再需要政策時，請將其刪除。
+  如需政策建立的詳細資訊，請參閱《[IAM 使用者指南》中的建立](https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_create.html) [IAM 政策和 IAM](https://docs.aws.amazon.com/IAM/latest/UserGuide/) [JSON 政策參考](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies.html) 

# 顯示 IAM 受管政策的政策文件
<a name="iam-policies-display"></a>

此範例說明如何使用 適用於 .NET 的 AWS SDK 來顯示政策文件。應用程式會建立 IAM 用戶端物件、尋找指定 IAM 受管政策的預設版本，然後在 JSON 中顯示政策文件。

下列各節提供此範例的程式碼片段。之後會顯示[範例的完整程式碼](#iam-policies-display-complete-code)，並可依原樣建置和執行。

**Topics**
+ [

## 尋找預設版本
](#iam-policies-display-version)
+ [

## 顯示政策文件
](#iam-policies-display-doc)
+ [

## 完成程式碼
](#iam-policies-display-complete-code)

## 尋找預設版本
<a name="iam-policies-display-version"></a>

下列程式碼片段會尋找指定 IAM 政策的預設版本。

[本主題結尾](#iam-policies-display-complete-code)的範例顯示此程式碼片段正在使用中。

```
    //
    // Method to determine the default version of an IAM policy
    // Returns a string with the version
    private static async Task<string> GetDefaultVersion(
      IAmazonIdentityManagementService iamClient, string policyArn)
    {
      // Retrieve all the versions of this policy
      string defaultVersion = string.Empty;
      ListPolicyVersionsResponse reponseVersions =
        await iamClient.ListPolicyVersionsAsync(new ListPolicyVersionsRequest{
          PolicyArn = policyArn});

      // Find the default version
      foreach(PolicyVersion version in reponseVersions.Versions)
      {
        if(version.IsDefaultVersion)
        {
          defaultVersion = version.VersionId;
          break;
        }
      }

      return defaultVersion;
    }
```

## 顯示政策文件
<a name="iam-policies-display-doc"></a>

下列程式碼片段會以指定 IAM 政策的 JSON 顯示政策文件。

[本主題結尾](#iam-policies-display-complete-code)的範例顯示此程式碼片段正在使用中。

```
    //
    // Method to retrieve and display the policy document of an IAM policy
    private static async Task ShowPolicyDocument(
      IAmazonIdentityManagementService iamClient, string policyArn, string defaultVersion)
    {
      // Retrieve the policy document of the default version
      GetPolicyVersionResponse responsePolicy =
        await iamClient.GetPolicyVersionAsync(new GetPolicyVersionRequest{
          PolicyArn = policyArn,
          VersionId = defaultVersion});

      // Display the policy document (in JSON)
      Console.WriteLine($"Version {defaultVersion} of the policy (in JSON format):");
      Console.WriteLine(
        $"{HttpUtility.UrlDecode(responsePolicy.PolicyVersion.Document)}");
    }
```

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

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

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

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

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

  [AmazonIdentityManagementServiceClient](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/IAM/TIAMServiceClient.html) 類別
+ 命名空間 [Amazon.IdentityManagement.Model](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/IAM/NIAMModel.html)

  類別 [GetPolicyVersionRequest](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/IAM/TGetPolicyVersionRequest.html)

  類別 [GetPolicyVersionResponse](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/IAM/TGetPolicyVersionResponse.html)

  類別 [ListPolicyVersionsRequest](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/IAM/TListPolicyVersionsRequest.html)

  類別 [ListPolicyVersionsResponse](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/IAM/TListPolicyVersionsResponse.html)

  類別[PolicyVersion](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/IAM/TPolicyVersion.html)

### 程式碼
<a name="w2aac19c15c19c23c19b7b1"></a>

```
using System;
using System.Web;
using System.Threading.Tasks;
using Amazon.IdentityManagement;
using Amazon.IdentityManagement.Model;

namespace IamDisplayPolicyJson
{
  class Program
  {
    static async Task Main(string[] args)
    {
      // Parse the command line and show help if necessary
      if(args.Length != 1)
      {
        Console.WriteLine("\nUsage: IamDisplayPolicyJson policy-arn");
        Console.WriteLine("   policy-arn: The ARN of the policy to retrieve.");
        return;
      }
      if(!args[0].StartsWith("arn:"))
      {
        Console.WriteLine("\nCould not find policy ARN in the command-line arguments:");
        Console.WriteLine($"{args[0]}");
        return;
      }

      // Create an IAM service client
      var iamClient = new AmazonIdentityManagementServiceClient();

      // Retrieve and display the policy document of the given policy
      string defaultVersion = await GetDefaultVersion(iamClient, args[0]);
      if(string.IsNullOrEmpty(defaultVersion))
        Console.WriteLine($"Could not find the default version for policy {args[0]}.");
      else
        await ShowPolicyDocument(iamClient, args[0], defaultVersion);
    }


    //
    // Method to determine the default version of an IAM policy
    // Returns a string with the version
    private static async Task<string> GetDefaultVersion(
      IAmazonIdentityManagementService iamClient, string policyArn)
    {
      // Retrieve all the versions of this policy
      string defaultVersion = string.Empty;
      ListPolicyVersionsResponse reponseVersions =
        await iamClient.ListPolicyVersionsAsync(new ListPolicyVersionsRequest{
          PolicyArn = policyArn});

      // Find the default version
      foreach(PolicyVersion version in reponseVersions.Versions)
      {
        if(version.IsDefaultVersion)
        {
          defaultVersion = version.VersionId;
          break;
        }
      }

      return defaultVersion;
    }


    //
    // Method to retrieve and display the policy document of an IAM policy
    private static async Task ShowPolicyDocument(
      IAmazonIdentityManagementService iamClient, string policyArn, string defaultVersion)
    {
      // Retrieve the policy document of the default version
      GetPolicyVersionResponse responsePolicy =
        await iamClient.GetPolicyVersionAsync(new GetPolicyVersionRequest{
          PolicyArn = policyArn,
          VersionId = defaultVersion});

      // Display the policy document (in JSON)
      Console.WriteLine($"Version {defaultVersion} of the policy (in JSON format):");
      Console.WriteLine(
        $"{HttpUtility.UrlDecode(responsePolicy.PolicyVersion.Document)}");
    }
  }
}
```

# 使用 IAM 角色授予存取權
<a name="net-dg-hosm"></a>

本教學課程說明如何使用 適用於 .NET 的 AWS SDK 在 Amazon EC2 執行個體上啟用 IAM 角色。

## 概觀
<a name="hosm-overview"></a>

對 的所有請求 AWS 都必須使用 發行的登入資料以密碼編譯方式簽署 AWS。因此，您需要策略來管理在 Amazon EC2 執行個體上執行之應用程式的登入資料。您必須安全地分發、存放和輪換這些登入資料，同時讓應用程式能夠存取這些登入資料。

透過 IAM 角色，您可以有效地管理這些登入資料。您可以建立 IAM 角色，並使用應用程式所需的許可進行設定，然後將該角色連接到 EC2 執行個體。若要進一步了解使用 IAM 角色的好處，請參閱《[Amazon EC2 使用者指南](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/iam-roles-for-amazon-ec2.html)[》中的 Amazon EC2 的 IAM ](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/)角色。另請參閱《[IAM 使用者指南》中的 IAM 角色](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles.html)相關資訊。

對於使用 建置的應用程式 適用於 .NET 的 AWS SDK，當應用程式建構 AWS 服務的用戶端物件時，物件會從數個潛在來源搜尋登入資料。其搜尋的順序會顯示在 中[憑證和設定檔解析](creds-assign.md)。

如果用戶端物件找不到任何其他來源的登入資料，則會擷取具有與已設定為 IAM 角色且位於 EC2 執行個體中繼資料中相同許可的臨時登入資料。這些登入資料用於 AWS 從用戶端物件呼叫 。

## 關於本教學
<a name="about-hosm-tutorial"></a>

遵循本教學課程時，您可以使用 適用於 .NET 的 AWS SDK （和其他工具） 啟動已連接 IAM 角色的 Amazon EC2 執行個體，然後使用 IAM 角色的許可查看執行個體上的應用程式。

**Topics**
+ [

## 概觀
](#hosm-overview)
+ [

## 關於本教學
](#about-hosm-tutorial)
+ [

## 建立範例 Amazon S3 應用程式
](#net-dg-hosm-sample-s3-app)
+ [

## 建立 IAM 角色
](#net-dg-hosm-create-the-role)
+ [

## 啟動 EC2 執行個體並連接 IAM 角色
](#net-dg-hosm-launch-ec2-instance)
+ [

## 連線至 EC2 執行個體
](#net-dg-hosm-connect)
+ [

## 在 EC2 執行個體上執行範例應用程式
](#net-dg-hosm-run-the-app)
+ [

## 清除
](#net-dg-hosm-cleanup)

## 建立範例 Amazon S3 應用程式
<a name="net-dg-hosm-sample-s3-app"></a>

此範例應用程式會從 Amazon S3 擷取物件。若要執行應用程式，您需要下列項目：
+ 包含文字檔案的 Amazon S3 儲存貯體。
+ AWS 開發機器上的登入資料，可讓您存取 儲存貯體。

如需有關建立 Amazon S3 儲存貯體和上傳物件的資訊，請參閱 [Amazon Simple Storage Service 使用者指南](https://docs.aws.amazon.com/AmazonS3/latest/userguide/)。如需 AWS 登入資料的資訊，請參閱 [使用 設定 SDK 身分驗證 AWS](creds-idc.md)。

使用下列程式碼建立 .NET Core 專案。然後在開發機器上測試應用程式。

**注意**  
在您的開發機器上安裝了 .NET Core Runtime，可讓您在不發佈的情況下執行應用程式。在本教學稍後建立 EC2 執行個體時，您可以選擇在執行個體上安裝 .NET Core Runtime。這為您提供了類似的體驗和較小的檔案傳輸。  
 不過，您也可以選擇不要在執行個體上安裝 .NET Core Runtime。如果您選擇此動作，則必須發佈應用程式，以便在將應用程式轉移到執行個體時包含所有相依性。

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

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

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

  [AmazonS3Client](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/S3/TS3Client.html) 類別
+ 命名空間 [Amazon.S3.Model](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/S3/NS3Model.html)

  類別 [GetObjectResponse](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/S3/TGetObjectResponse.html)

### 程式碼
<a name="w2aac19c15c19c25c17c15b1"></a>

```
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using Amazon.S3;
using Amazon.S3.Model;

namespace S3GetTextItem
{
  // = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
  // Class to retrieve a text file from an S3 bucket and write it to a local file
  class Program
  {
    static async Task Main(string[] args)
    {
      // Parse the command line and show help if necessary
      var parsedArgs = CommandLine.Parse(args);
      if(parsedArgs.Count == 0)
      {
        PrintHelp();
        return;
      }

      // Get the application arguments from the parsed list
      string bucket =
        CommandLine.GetArgument(parsedArgs, null, "-b", "--bucket-name");
      string item =
        CommandLine.GetArgument(parsedArgs, null, "-t", "--text-object");
      string outFile =
        CommandLine.GetArgument(parsedArgs, null, "-o", "--output-filename");
      if(   string.IsNullOrEmpty(bucket)
         || string.IsNullOrEmpty(item)
         || string.IsNullOrEmpty(outFile))
        CommandLine.ErrorExit(
          "\nOne or more of the required arguments is missing or incorrect." +
          "\nRun the command with no arguments to see help.");

      // Create the S3 client object and get the file object from the bucket.
      var response = await GetObject(new AmazonS3Client(), bucket, item);

      // Write the contents of the file object to the given output file.
      var reader = new StreamReader(response.ResponseStream);
      string contents = reader.ReadToEnd();
      using (var s = new FileStream(outFile, FileMode.Create))
      using (var writer = new StreamWriter(s))
        writer.WriteLine(contents);
    }


    //
    // Method to get an object from an S3 bucket.
    private static async Task<GetObjectResponse> GetObject(
      IAmazonS3 s3Client, string bucket, string item)
    {
        Console.WriteLine($"Retrieving {item} from bucket {bucket}.");
        return await s3Client.GetObjectAsync(bucket, item);
    }


    //
    // Command-line help
    private static void PrintHelp()
    {
      Console.WriteLine(
        "\nUsage: S3GetTextItem -b <bucket-name> -t <text-object> -o <output-filename>" +
        "\n  -b, --bucket-name: The name of the S3 bucket." +
        "\n  -t, --text-object: The name of the text object in the bucket." +
        "\n  -o, --output-filename: The name of the file to write the text to.");
    }
  }


  // = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
  // Class that represents a command line on the console or terminal.
  // (This is the same for all examples. When you have seen it once, you can ignore it.)
  static class CommandLine
  {
    //
    // Method to parse a command line of the form: "--key value" or "-k value".
    //
    // Parameters:
    // - args: The command-line arguments passed into the application by the system.
    //
    // Returns:
    // A Dictionary with string Keys and Values.
    //
    // If a key is found without a matching value, Dictionary.Value is set to the key
    //  (including the dashes).
    // If a value is found without a matching key, Dictionary.Key is set to "--NoKeyN",
    //  where "N" represents sequential numbers.
    public static Dictionary<string,string> Parse(string[] args)
    {
      var parsedArgs = new Dictionary<string,string>();
      int i = 0, n = 0;
      while(i < args.Length)
      {
        // If the first argument in this iteration starts with a dash it's an option.
        if(args[i].StartsWith("-"))
        {
          var key = args[i++];
          var value = key;

          // Check to see if there's a value that goes with this option?
          if((i < args.Length) && (!args[i].StartsWith("-"))) value = args[i++];
          parsedArgs.Add(key, value);
        }

        // If the first argument in this iteration doesn't start with a dash, it's a value
        else
        {
          parsedArgs.Add("--NoKey" + n.ToString(), args[i++]);
          n++;
        }
      }

      return parsedArgs;
    }

    //
    // Method to get an argument from the parsed command-line arguments
    //
    // Parameters:
    // - parsedArgs: The Dictionary object returned from the Parse() method (shown above).
    // - defaultValue: The default string to return if the specified key isn't in parsedArgs.
    // - keys: An array of keys to look for in parsedArgs.
    public static string GetArgument(
      Dictionary<string,string> parsedArgs, string defaultReturn, params string[] keys)
    {
      string retval = null;
      foreach(var key in keys)
        if(parsedArgs.TryGetValue(key, out retval)) break;
      return retval ?? defaultReturn;
    }

    //
    // Method to exit the application with an error.
    public static void ErrorExit(string msg, int code=1)
    {
      Console.WriteLine("\nError");
      Console.WriteLine(msg);
      Environment.Exit(code);
    }
  }

}
```

如果需要，您可以暫時移除在開發機器上使用的登入資料，以查看應用程式如何回應。（但請務必在完成時還原登入資料。)

## 建立 IAM 角色
<a name="net-dg-hosm-create-the-role"></a>

建立具有適當許可的 IAM 角色來存取 Amazon S3。

1. 開啟 [IAM 主控台](https://console.aws.amazon.com/iam/)。

1. 在導覽窗格中，選擇**角色**，然後選擇**建立角色**。

1. 選取**AWS 服務**，尋找並選擇 **EC2**，然後選擇**下一步：許可**。

1. 在**連接許可政策**下，尋找並選取 **AmazonS3ReadOnlyAccess**。如果您想要的話，請檢閱政策，然後選擇**下一步：標籤**。

1. 如果需要，請新增標籤，然後選擇**下一步：檢閱**。

1. 輸入該角色的名稱和說明，然後選擇 **Create role** (建立新角色)。請記住此名稱，因為在您啟動 EC2 執行個體時需要用到。

## 啟動 EC2 執行個體並連接 IAM 角色
<a name="net-dg-hosm-launch-ec2-instance"></a>

使用您先前建立的 IAM 角色啟動 EC2 執行個體。您可以透過下列方式執行此操作。
+ **使用 EC2 主控台**

  若要使用 EC2 主控台啟動執行個體，請參閱《[Amazon EC2 使用者指南](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/)》中的[使用新的啟動執行個體精靈啟動執行個體](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-launch-instance-wizard.html)。

  當您查看啟動頁面時，您至少應該展開**進階詳細資訊**窗格，以便您可以指定先前在 IAM **執行個體描述檔中建立的 IAM** 角色。
+ **使用 適用於 .NET 的 AWS SDK**

  如需相關資訊，請參閱 [啟動 Amazon EC2 執行個體](run-instance.md)，包括該主題[其他考量](run-instance.md#run-instance-additional)接近結尾的 。

若要啟動已連接 IAM 角色的 EC2 執行個體，IAM 使用者的組態必須包含特定許可。如需所需許可的詳細資訊，請參閱《[Amazon EC2 使用者指南](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/)》中的[授予使用者將 IAM 角色傳遞至執行個體的許可](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/iam-roles-for-amazon-ec2.html#permission-to-pass-iam-roles)。

## 連線至 EC2 執行個體
<a name="net-dg-hosm-connect"></a>

連線至 EC2 執行個體，以便您可以將範例應用程式轉移至該執行個體，然後執行應用程式。您需要包含用來啟動執行個體之金鑰對私有部分的 檔案，也就是 PEM 檔案。

如需連接至執行個體的資訊，請參閱《[Amazon EC2 使用者指南](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/)》中的[連接至 Linux 執行個體](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/connect-to-linux-instance.html)或[連接至 Windows 執行個體](https://docs.aws.amazon.com/AWSEC2/latest/WindowsGuide/connecting_to_windows_instance.html)。當您連線時，請以可讓您將檔案從開發機器傳輸到執行個體的方式執行此操作。

如果您在 Windows 上使用 Visual Studio，您也可以使用 Toolkit for Visual Studio 連線至執行個體。如需詳細資訊，請參閱 AWS Toolkit for Visual Studio 《 使用者指南》中的[連線至 Amazon EC2 執行個體](https://docs.aws.amazon.com/toolkit-for-visual-studio/latest/user-guide/tkv-ec2-ami.html#connect-ec2)。

## 在 EC2 執行個體上執行範例應用程式
<a name="net-dg-hosm-run-the-app"></a>

1. 將應用程式檔案從本機磁碟機複製到執行個體。

   傳輸哪些檔案取決於您建置應用程式的方式，以及執行個體是否已安裝 .NET Core Runtime。如需有關如何將檔案傳輸至執行個體的資訊，請參閱《[Amazon EC2 使用者指南](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/)》中的[連線至 Linux 執行個體](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/connect-to-linux-instance.html) （請參閱適當的子區段） 或[將檔案傳輸至 Windows 執行個體](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/connect-to-linux-instanceWindowsFileTransfer.html)。

1. 啟動應用程式，並確認其執行的結果與開發機器上的結果相同。

1. 確認應用程式使用 IAM 角色提供的登入資料。

   1. 開啟 [Amazon EC2 主控台](https://console.aws.amazon.com/ec2/)。

   1. 選取執行個體，並透過**動作**、**執行個體設定**、**連接/取代 IAM 角色來分離 IAM 角色**。

   1. 再次執行應用程式，並查看它傳回授權錯誤。

## 清除
<a name="net-dg-hosm-cleanup"></a>

完成本教學課程後，如果您不再需要您建立的 EC2 執行個體，請務必終止執行個體，以避免不必要的成本。您可以在 [Amazon EC2 主控台](https://console.aws.amazon.com/ec2/)或以程式設計方式執行此操作，如中所述[終止 Amazon EC2 執行個體](terminate-instance.md)。如果您願意，也可以刪除您為此教學課程建立的其他資源。這些可能包括 IAM 角色、EC2 金鑰對和 PEM 檔案、安全群組等。

# 使用 Amazon Simple Storage Service 網際網路儲存
<a name="s3-apis-intro"></a>

 適用於 .NET 的 AWS SDK 支援 [Amazon S3](https://aws.amazon.com/s3/)，這是網際網路的儲存體。此服務旨在降低開發人員進行網路規模運算的難度。

## API
<a name="w2aac19c15c21b5"></a>

為 Amazon S3 用戶端 適用於 .NET 的 AWS SDK 提供 APIs。APIs 可讓您使用 Amazon S3 資源，例如儲存貯體和項目。若要檢視 Amazon S3 的完整 APIs 集，請參閱以下內容：
+ [適用於 .NET 的 AWS SDK API 參考](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/) （並捲動至「Amazon.S3」)。
+ [Amazon.Extensions.S3.Encryption](https://aws.github.io/amazon-s3-encryption-client-dotnet/api/Amazon.Extensions.S3.Encryption.html) 文件

Amazon S3 APIs 由下列 NuGet 套件提供：
+ [AWSSDK.S3](https://www.nuget.org/packages/AWSSDK.S3)
+ [Amazon.Extensions.S3.Encryption](https://www.nuget.org/packages/Amazon.Extensions.S3.Encryption)

## 先決條件
<a name="w2aac19c15c21b7"></a>

開始之前，請確定您已[設定環境和專案](net-dg-config.md)。也請檢閱 中的資訊[開發套件功能](net-dg-sdk-features.md)。

## 本文件中的範例
<a name="s3-apis-examples"></a>

本文件中的下列主題說明如何使用 適用於 .NET 的 AWS SDK 來使用 Amazon S3。
+ [使用 KMS 金鑰進行 S3 加密](kms-keys-s3-encryption.md)

## 其他文件中的範例
<a name="s3-apis-examples-other"></a>

[Amazon S3 開發人員指南](https://docs.aws.amazon.com/AmazonS3/latest/userguide/)的下列連結提供如何使用 適用於 .NET 的 AWS SDK 來使用 Amazon S3 的其他範例。

**注意**  
雖然這些範例和其他程式設計考量是針對 適用於 .NET 的 AWS SDK 使用 .NET Framework 的 第 3 版所建立，但它們也適用於 適用於 .NET 的 AWS SDK 使用 .NET Core 的較新版本。有時需要對程式碼進行小型調整。

**Amazon S3 程式設計範例**
+  [管理 ACL](https://docs.aws.amazon.com/AmazonS3/latest/dev/acl-using-dot-net-sdk.html) 
+  [建立儲存貯體](https://docs.aws.amazon.com/AmazonS3/latest/dev/create-bucket-get-location-example.html#create-bucket-get-location-dotnet) 
+  [上傳物件](https://docs.aws.amazon.com/AmazonS3/latest/dev/UploadObjSingleOpNET.html) 
+  [使用高階 API 進行分段上傳 ([Amazon.S3.Transfer.TransferUtility](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/S3/TTransferUtility.html))](https://docs.aws.amazon.com/AmazonS3/latest/dev/usingHLmpuDotNet.html) 
+  [使用低階 API 執行分段上傳](https://docs.aws.amazon.com/AmazonS3/latest/dev/usingLLmpuDotNet.html) 
+  [列出物件](https://docs.aws.amazon.com/AmazonS3/latest/dev/list-obj-version-enabled-bucket.html#list-obj-version-enabled-bucket-sdk-examples) 
+  [列出金鑰](https://docs.aws.amazon.com/AmazonS3/latest/dev/ListingObjectKeysUsingNetSDK.html) 
+  [取得物件](https://docs.aws.amazon.com/AmazonS3/latest/dev/RetrievingObjectUsingNetSDK.html) 
+  [複製物件](https://docs.aws.amazon.com/AmazonS3/latest/dev/CopyingObjectUsingNetSDK.html) 
+  [使用分段上傳 API 複製物件](https://docs.aws.amazon.com/AmazonS3/latest/dev/CopyingObjctsUsingLLNetMPUapi.html) 
+  [刪除物件](https://docs.aws.amazon.com/AmazonS3/latest/dev/DeletingOneObjectUsingNetSDK.html) 
+  [刪除多個物件](https://docs.aws.amazon.com/AmazonS3/latest/dev/DeletingMultipleObjectsUsingNetSDK.html) 
+  [還原物件](https://docs.aws.amazon.com/AmazonS3/latest/dev/restore-object-dotnet.html) 
+  [設定儲存貯體的通知](https://docs.aws.amazon.com/AmazonS3/latest/dev/ways-to-add-notification-config-to-bucket.html) 
+  [管理物件的生命週期](https://docs.aws.amazon.com/AmazonS3/latest/dev/manage-lifecycle-using-dot-net.html) 
+  [產生預先簽章的物件 URL](https://docs.aws.amazon.com/AmazonS3/latest/dev/ShareObjectPreSignedURLDotNetSDK.html) 
+  [管理網站](https://docs.aws.amazon.com/AmazonS3/latest/dev/ConfigWebSiteDotNet.html) 
+  [啟用跨來源資源分享 (CORS)](https://docs.aws.amazon.com/AmazonS3/latest/dev/ManageCorsUsingDotNet.html) 

**其他程式設計考量事項**
+  [使用 適用於 .NET 的 AWS SDK 進行 Amazon S3 程式設計](https://docs.aws.amazon.com/AmazonS3/latest/dev/UsingTheMPDotNetAPI.html) 
+  [使用 IAM 使用者暫時性登入資料提出請求](https://docs.aws.amazon.com/AmazonS3/latest/dev/AuthUsingTempSessionTokenDotNet.html) 
+  [使用聯合身分使用者暫時登入資料提出請求](https://docs.aws.amazon.com/AmazonS3/latest/dev/AuthUsingTempFederationTokenDotNet.html) 
+  [指定伺服器端加密](https://docs.aws.amazon.com/AmazonS3/latest/dev/SSEUsingDotNetSDK.html) 
+  [使用客戶提供的加密金鑰指定伺服器端加密](https://docs.aws.amazon.com/AmazonS3/latest/dev/sse-c-using-dot-net-sdk.html) 

# 在 中使用 AWS KMS 金鑰進行 Amazon S3 加密 適用於 .NET 的 AWS SDK
<a name="kms-keys-s3-encryption"></a>

此範例說明如何使用 AWS Key Management Service 金鑰來加密 Amazon S3 物件。應用程式會建立客戶主金鑰 (CMK)，並使用它來建立 [AmazonS3EncryptionClientV2](https://aws.github.io/amazon-s3-encryption-client-dotnet/api/Amazon.Extensions.S3.Encryption.AmazonS3EncryptionClientV2.html) 物件以進行用戶端加密。應用程式使用該用戶端，從現有 Amazon S3 儲存貯體中的指定文字檔案建立加密物件。然後，它會解密物件並顯示其內容。

**警告**  
稱為 的類似類別`AmazonS3EncryptionClient`已棄用，且比 `AmazonS3EncryptionClientV2`類別較不安全。若要遷移使用 的現有程式碼`AmazonS3EncryptionClient`，請參閱 [S3 加密用戶端遷移 (V1 到 V2)](s3-encryption-migration-v1-v2.md)。

**Topics**
+ [

## 建立加密資料
](#kms-s3-enc-mat)
+ [

## 建立和加密 Amazon S3 物件
](#kms-s3-create-ojbect)
+ [

## 完成程式碼
](#kms-s3-complete-code)
+ [

## 其他考量
](#kms-s3-additional)

## 建立加密資料
<a name="kms-s3-enc-mat"></a>

下列程式碼片段會建立包含 KMS 金鑰 ID 的`EncryptionMaterials`物件。

[本主題結尾](#kms-s3-complete-code)的範例顯示此程式碼片段正在使用中。

```
      // Create a customer master key (CMK) and store the result
      CreateKeyResponse createKeyResponse =
        await new AmazonKeyManagementServiceClient().CreateKeyAsync(new CreateKeyRequest());
      var kmsEncryptionContext = new Dictionary<string, string>();
      var kmsEncryptionMaterials = new EncryptionMaterialsV2(
        createKeyResponse.KeyMetadata.KeyId, KmsType.KmsContext, kmsEncryptionContext);
```

## 建立和加密 Amazon S3 物件
<a name="kms-s3-create-ojbect"></a>

下列程式碼片段會建立使用先前建立之加密資料的 `AmazonS3EncryptionClientV2` 物件。然後，它會使用用戶端來建立和加密新的 Amazon S3 物件。

[本主題結尾](#kms-s3-complete-code)的範例顯示此程式碼片段正在使用中。

```
    //
    // Method to create and encrypt an object in an S3 bucket
    static async Task<GetObjectResponse> CreateAndRetrieveObjectAsync(
      EncryptionMaterialsV2 materials, string bucketName,
      string fileName, string itemName)
    {
      // CryptoStorageMode.ObjectMetadata is required for KMS EncryptionMaterials
      var config = new AmazonS3CryptoConfigurationV2(SecurityProfile.V2AndLegacy)
      {
        StorageMode = CryptoStorageMode.ObjectMetadata
      };
      var s3EncClient = new AmazonS3EncryptionClientV2(config, materials);

      // Create, encrypt, and put the object
      await s3EncClient.PutObjectAsync(new PutObjectRequest
      {
        BucketName = bucketName,
        Key = itemName,
        ContentBody = File.ReadAllText(fileName)
      });

      // Get, decrypt, and return the object
      return await s3EncClient.GetObjectAsync(new GetObjectRequest
      {
        BucketName = bucketName,
        Key = itemName
      });
    }
```

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

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

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

NuGet 套件：
+ [Amazon.Extensions.S3.Encryption](https://www.nuget.org/packages/Amazon.Extensions.S3.Encryption)

程式設計元素：
+ 命名空間 [Amazon.Extensions.S3.Encryption](https://aws.github.io/amazon-s3-encryption-client-dotnet/api/Amazon.Extensions.S3.Encryption.html)

  [AmazonS3EncryptionClientV2](https://aws.github.io/amazon-s3-encryption-client-dotnet/api/Amazon.Extensions.S3.Encryption.AmazonS3EncryptionClientV2.html) 類別

  [AmazonS3CryptoConfigurationV2](https://aws.github.io/amazon-s3-encryption-client-dotnet/api/Amazon.Extensions.S3.Encryption.AmazonS3CryptoConfigurationV2.html) 類別

  類別 [CryptoStorageMode](https://aws.github.io/amazon-s3-encryption-client-dotnet/api/Amazon.Extensions.S3.Encryption.CryptoStorageMode.html)

  類別 [EncryptionMaterialsV2](https://aws.github.io/amazon-s3-encryption-client-dotnet/api/Amazon.Extensions.S3.Encryption.EncryptionMaterialsV2.html)
+ 命名空間 [Amazon.Extensions.S3.Encryption.Primitives](https://aws.github.io/amazon-s3-encryption-client-dotnet/api/Amazon.Extensions.S3.Encryption.Primitives.html)

  類別 [KmsType](https://aws.github.io/amazon-s3-encryption-client-dotnet/api/Amazon.Extensions.S3.Encryption.Primitives.KmsType.html)
+ 命名空間 [Amazon.S3.Model](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/S3/NS3Model.html)

  類別 [GetObjectRequest](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/S3/TGetObjectRequest.html)

  類別 [GetObjectResponse](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/S3/TGetObjectResponse.html)

  類別 [PutObjectRequest](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/S3/TPutObjectRequest.html)
+ 命名空間 [Amazon.KeyManagementService](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/KeyManagementService/NKeyManagementService.html)

  [AmazonKeyManagementServiceClient](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/KeyManagementService/TKeyManagementServiceClient.html) 類別
+ 命名空間 [Amazon.KeyManagementService.Model](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/KeyManagementService/NKeyManagementServiceModel.html)

  類別 [CreateKeyRequest](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/KeyManagementService/TCreateKeyRequest.html)

  類別 [CreateKeyResponse](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/KeyManagementService/TCreateKeyResponse.html)

### 程式碼
<a name="w2aac19c15c21c13c15b7b1"></a>

```
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using Amazon.Extensions.S3.Encryption;
using Amazon.Extensions.S3.Encryption.Primitives;
using Amazon.S3.Model;
using Amazon.KeyManagementService;
using Amazon.KeyManagementService.Model;

namespace KmsS3Encryption
{
  // = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
  // Class to store text in an encrypted S3 object.
  class Program
  {
    private const int MaxArgs = 3;

    public static async Task Main(string[] args)
    {
      // Parse the command line and show help if necessary
      var parsedArgs = CommandLine.Parse(args);
      if((parsedArgs.Count == 0) || (parsedArgs.Count > MaxArgs))
      {
        PrintHelp();
        return;
      }

      // Get the application arguments from the parsed list
      string bucketName =
        CommandLine.GetArgument(parsedArgs, null, "-b", "--bucket-name");
      string fileName =
        CommandLine.GetArgument(parsedArgs, null, "-f", "--file-name");
      string itemName =
        CommandLine.GetArgument(parsedArgs, null, "-i", "--item-name");
      if(string.IsNullOrEmpty(bucketName) || (string.IsNullOrEmpty(fileName)))
        CommandLine.ErrorExit(
          "\nOne or more of the required arguments is missing or incorrect." +
          "\nRun the command with no arguments to see help.");
      if(!File.Exists(fileName))
        CommandLine.ErrorExit($"\nThe given file {fileName} doesn't exist.");
      if(string.IsNullOrEmpty(itemName))
        itemName = Path.GetFileName(fileName);

      // Create a customer master key (CMK) and store the result
      CreateKeyResponse createKeyResponse =
        await new AmazonKeyManagementServiceClient().CreateKeyAsync(new CreateKeyRequest());
      var kmsEncryptionContext = new Dictionary<string, string>();
      var kmsEncryptionMaterials = new EncryptionMaterialsV2(
        createKeyResponse.KeyMetadata.KeyId, KmsType.KmsContext, kmsEncryptionContext);

      // Create the object in the bucket, then display the content of the object
      var putObjectResponse =
        await CreateAndRetrieveObjectAsync(kmsEncryptionMaterials, bucketName, fileName, itemName);
      Stream stream = putObjectResponse.ResponseStream;
      StreamReader reader = new StreamReader(stream);
      Console.WriteLine(reader.ReadToEnd());
    }


    //
    // Method to create and encrypt an object in an S3 bucket
    static async Task<GetObjectResponse> CreateAndRetrieveObjectAsync(
      EncryptionMaterialsV2 materials, string bucketName,
      string fileName, string itemName)
    {
      // CryptoStorageMode.ObjectMetadata is required for KMS EncryptionMaterials
      var config = new AmazonS3CryptoConfigurationV2(SecurityProfile.V2AndLegacy)
      {
        StorageMode = CryptoStorageMode.ObjectMetadata
      };
      var s3EncClient = new AmazonS3EncryptionClientV2(config, materials);

      // Create, encrypt, and put the object
      await s3EncClient.PutObjectAsync(new PutObjectRequest
      {
        BucketName = bucketName,
        Key = itemName,
        ContentBody = File.ReadAllText(fileName)
      });

      // Get, decrypt, and return the object
      return await s3EncClient.GetObjectAsync(new GetObjectRequest
      {
        BucketName = bucketName,
        Key = itemName
      });
    }


    //
    // Command-line help
    private static void PrintHelp()
    {
      Console.WriteLine(
        "\nUsage: KmsS3Encryption -b <bucket-name> -f <file-name> [-i <item-name>]" +
        "\n  -b, --bucket-name: The name of an existing S3 bucket." +
        "\n  -f, --file-name: The name of a text file with content to encrypt and store in S3." +
        "\n  -i, --item-name: The name you want to use for the item." +
        "\n      If item-name isn't given, file-name will be used.");
    }

  }

  // = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
  // Class that represents a command line on the console or terminal.
  // (This is the same for all examples. When you have seen it once, you can ignore it.)
  static class CommandLine
  {
    //
    // Method to parse a command line of the form: "--key value" or "-k value".
    //
    // Parameters:
    // - args: The command-line arguments passed into the application by the system.
    //
    // Returns:
    // A Dictionary with string Keys and Values.
    //
    // If a key is found without a matching value, Dictionary.Value is set to the key
    //  (including the dashes).
    // If a value is found without a matching key, Dictionary.Key is set to "--NoKeyN",
    //  where "N" represents sequential numbers.
    public static Dictionary<string,string> Parse(string[] args)
    {
      var parsedArgs = new Dictionary<string,string>();
      int i = 0, n = 0;
      while(i < args.Length)
      {
        // If the first argument in this iteration starts with a dash it's an option.
        if(args[i].StartsWith("-"))
        {
          var key = args[i++];
          var value = key;

          // Check to see if there's a value that goes with this option?
          if((i < args.Length) && (!args[i].StartsWith("-"))) value = args[i++];
          parsedArgs.Add(key, value);
        }

        // If the first argument in this iteration doesn't start with a dash, it's a value
        else
        {
          parsedArgs.Add("--NoKey" + n.ToString(), args[i++]);
          n++;
        }
      }

      return parsedArgs;
    }

    //
    // Method to get an argument from the parsed command-line arguments
    //
    // Parameters:
    // - parsedArgs: The Dictionary object returned from the Parse() method (shown above).
    // - defaultValue: The default string to return if the specified key isn't in parsedArgs.
    // - keys: An array of keys to look for in parsedArgs.
    public static string GetArgument(
      Dictionary<string,string> parsedArgs, string defaultReturn, params string[] keys)
    {
      string retval = null;
      foreach(var key in keys)
        if(parsedArgs.TryGetValue(key, out retval)) break;
      return retval ?? defaultReturn;
    }

    //
    // Method to exit the application with an error.
    public static void ErrorExit(string msg, int code=1)
    {
      Console.WriteLine("\nError");
      Console.WriteLine(msg);
      Environment.Exit(code);
    }
  }

}
```

## 其他考量
<a name="kms-s3-additional"></a>
+ 您可以檢查此範例的結果。若要這樣做，請前往 [Amazon S3 主控台](https://console.aws.amazon.com/s3)並開啟您提供給應用程式的儲存貯體。然後尋找新物件、下載它，然後在文字編輯器中開啟它。
+ [AmazonS3EncryptionClientV2](https://aws.github.io/amazon-s3-encryption-client-dotnet/api/Amazon.Extensions.S3.Encryption.AmazonS3EncryptionClientV2.html) 類別實作與標準`AmazonS3Client`類別相同的界面。這可讓您更輕鬆地將程式碼移植到 `AmazonS3EncryptionClientV2`類別，以便在用戶端中自動且透明地進行加密和解密。
+ 使用 AWS KMS 金鑰做為主金鑰的一個優點是您不需要儲存和管理自己的主金鑰；這由 完成 AWS。第二個優點是 的 `AmazonS3EncryptionClientV2`類別可與 的 `AmazonS3EncryptionClientV2`類別 適用於 .NET 的 AWS SDK 互通 適用於 Java 的 AWS SDK。這表示您可以使用 加密 適用於 Java 的 AWS SDK ，並使用 解密 適用於 .NET 的 AWS SDK，反之亦然。
**注意**  
的 `AmazonS3EncryptionClientV2`類別僅在中繼資料模式下執行時 適用於 .NET 的 AWS SDK 支援 KMS 主金鑰。`AmazonS3EncryptionClientV2` 類別 的指示檔案模式與 `AmazonS3EncryptionClientV2`類別 適用於 .NET 的 AWS SDK 不相容 適用於 Java 的 AWS SDK。
+ 如需使用 `AmazonS3EncryptionClientV2`類別進行用戶端加密，以及信封加密如何運作的詳細資訊，請參閱[使用 適用於 .NET 的 AWS SDK 和 Amazon S3 進行用戶端資料加密](https://aws.amazon.com/blogs/developer/client-side-data-encryption-with-aws-sdk-for-net-and-amazon-s3/)。

# 使用 Amazon Simple Notification Service 從雲端傳送通知
<a name="sns-apis-intro"></a>

**注意**  
本主題中的資訊專屬於以 .NET Framework 和 3.3 適用於 .NET 的 AWS SDK 版及更早版本為基礎的專案。

 適用於 .NET 的 AWS SDK 支援 Amazon Simple Notification Service (Amazon SNS)，這是一種 Web 服務，可讓應用程式、最終使用者和裝置立即從雲端傳送通知。如需詳細資訊，請參閱 [Amazon SNS](https://aws.amazon.com/sns/)。

## 列出您的 Amazon SNS 主題
<a name="sns-list-example"></a>

下列範例說明如何列出 Amazon SNS 主題、每個主題的訂閱，以及每個主題的屬性。此範例使用預設的 [AmazonSimpleNotificationServiceClient](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/SNS/TSNSClient.html)。

```
// using Amazon.SimpleNotificationService;
// using Amazon.SimpleNotificationService.Model;

var client = new AmazonSimpleNotificationServiceClient();
var request = new ListTopicsRequest();
var response = new ListTopicsResponse();

do
{
  response = client.ListTopics(request);

  foreach (var topic in response.Topics)
  {
    Console.WriteLine("Topic: {0}", topic.TopicArn);

    var subs = client.ListSubscriptionsByTopic(
      new ListSubscriptionsByTopicRequest
      {
        TopicArn = topic.TopicArn
      });

    var ss = subs.Subscriptions;

    if (ss.Any())
    {
      Console.WriteLine("  Subscriptions:");

      foreach (var sub in ss)
      {
        Console.WriteLine("    {0}", sub.SubscriptionArn);
      }
    }

    var attrs = client.GetTopicAttributes(
      new GetTopicAttributesRequest
      {
        TopicArn = topic.TopicArn
      }).Attributes;

    if (attrs.Any())
    {
      Console.WriteLine("  Attributes:");

      foreach (var attr in attrs)
      {
        Console.WriteLine("    {0} = {1}", attr.Key, attr.Value);
      }
    }

    Console.WriteLine();
  }

  request.NextToken = response.NextToken;

} while (!string.IsNullOrEmpty(response.NextToken));
```

## 傳送訊息至 Amazon SNS 主題
<a name="sns-send-message-example"></a>

下列範例示範如何傳送訊息至 Amazon SNS 主題。此範例採用一個引數，即 Amazon SNS 主題的 ARN。

```
using System;
using System.Linq;
using System.Threading.Tasks;

using Amazon;
using Amazon.SimpleNotificationService;
using Amazon.SimpleNotificationService.Model;

namespace SnsSendMessage
{
    class Program
    {
        static void Main(string[] args)
        {
            /* Topic ARNs must be in the correct format:
             *   arn:aws:sns:REGION:ACCOUNT_ID:NAME
             *
             *  where:
             *  REGION     is the region in which the topic is created, such as us-west-2
             *  ACCOUNT_ID is your (typically) 12-character account ID
             *  NAME       is the name of the topic
             */
            string topicArn = args[0];
            string message = "Hello at " + DateTime.Now.ToShortTimeString();

            var client = new AmazonSimpleNotificationServiceClient(region: Amazon.RegionEndpoint.USWest2);

            var request = new PublishRequest
            {
                Message = message,
                TopicArn = topicArn
            };

            try
            {
                var response = client.Publish(request);

                Console.WriteLine("Message sent to topic:");
                Console.WriteLine(message);
            }
            catch (Exception ex)
            {
                Console.WriteLine("Caught exception publishing request:");
                Console.WriteLine(ex.Message);
            }
        }
    }
}
```

請參閱 GitHub 上的[完整範例](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/.dotnet/example_code_legacy/SNS/SnsSendMessage.cs)，包括如何從命令列建立和執行範例的資訊。

## 傳送簡訊至一個電話號碼
<a name="sns-send-sms-example"></a>

以下範例說明如何傳送簡訊到電話號碼。此範例採用一個引數，即電話號碼，其必須採用註解中所述兩種格式之一。

```
using System;
using System.Linq;
using System.Threading.Tasks;
using Amazon;
using Amazon.SimpleNotificationService;
using Amazon.SimpleNotificationService.Model;

namespace SnsPublish
{
    class Program
    {
        static void Main(string[] args)
        {
            // US phone numbers must be in the correct format:
            // +1 (nnn) nnn-nnnn OR +1nnnnnnnnnn
            string number = args[0];
            string message = "Hello at " + DateTime.Now.ToShortTimeString();

            var client = new AmazonSimpleNotificationServiceClient(region: Amazon.RegionEndpoint.USWest2);
            var request = new PublishRequest
            {
                Message = message,
                PhoneNumber = number
            };

            try
            {
                var response = client.Publish(request);

                Console.WriteLine("Message sent to " + number + ":");
                Console.WriteLine(message);
            }
            catch (Exception ex)
            {
                Console.WriteLine("Caught exception publishing request:");
                Console.WriteLine(ex.Message);
            }
        }
    }
}
```

請參閱 GitHub 上的[完整範例](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/.dotnet/example_code_legacy/SNS/SnsPublish.cs)，包括如何從命令列建立和執行範例的資訊。

# 使用 Amazon SQS 傳送訊息
<a name="sqs-apis-intro"></a>

 適用於 .NET 的 AWS SDK 支援 [Amazon Simple Queue Service (Amazon SQS)](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/)，這是一種訊息佇列服務，可處理系統中元件之間的訊息或工作流程。

Amazon SQS 佇列提供一種機制，可讓您在微型服務、分散式系統和無伺服器應用程式等軟體元件之間傳送、存放和接收訊息。這可讓您解耦這類元件，讓您無需設計和操作自己的簡訊系統。如需有關佇列和訊息如何在 Amazon SQS 中運作的資訊，請參閱[《Amazon Simple Queue Service 開發人員指南》中的 Amazon SQS 教學](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-other-tutorials.html)課程和[基本 Amazon SQS 架構](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-basic-architecture.html)。 [https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/)

**重要**  
由於佇列的分散式性質，Amazon SQS 無法保證您會收到精確的訊息。如果您需要保留訊息順序，請使用 [Amazon SQS FIFO 佇列](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-fifo-queues.html)。

## API
<a name="w2aac19c15c25b9"></a>

為 Amazon SQS 用戶端 適用於 .NET 的 AWS SDK 提供 APIs。APIs 可讓您使用 Amazon SQS 功能，例如佇列和訊息。本節包含一些範例，顯示您在使用這些 APIs 時可遵循的模式。若要檢視完整的 APIs 集，請參閱 [適用於 .NET 的 AWS SDK API 參考](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/) （並捲動至「Amazon.SQS」)。

Amazon SQS APIs 由 [AWSSDK.SQS](https://www.nuget.org/packages/AWSSDK.SQS) NuGet 套件提供。

## 先決條件
<a name="w2aac19c15c25c11"></a>

開始之前，請確定您已[設定環境和專案](net-dg-config.md)。也請檢閱 中的資訊[開發套件功能](net-dg-sdk-features.md)。

## 主題
<a name="w2aac19c15c25c13"></a>

**Topics**
+ [

## API
](#w2aac19c15c25b9)
+ [

## 先決條件
](#w2aac19c15c25c11)
+ [

## 主題
](#w2aac19c15c25c13)
+ [建立佇列](CreateQueue.md)
+ [更新佇列](UpdateSqsQueue.md)
+ [刪除佇列](DeleteSqsQueue.md)
+ [傳送訊息](SendMessage.md)
+ [接收訊息](ReceiveMessage.md)

# 建立 Amazon SQS 佇列
<a name="CreateQueue"></a>

此範例說明如何使用 適用於 .NET 的 AWS SDK 來建立 Amazon SQS 佇列。如果您未提供無效[字母佇列](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-dead-letter-queues.html)的 ARN，應用程式會建立無效字母佇列。然後，它會建立標準訊息佇列，其中包含無效字母佇列 （您提供的佇列或建立的佇列）。

如果您未提供任何命令列引數，應用程式只會顯示所有現有佇列的相關資訊。

下列各節提供此範例的程式碼片段。之後會顯示[範例的完整程式碼](#CreateQueue-complete-code)，並可依原樣建置和執行。

**Topics**
+ [

## 顯示現有的佇列
](#CreateQueue-show-queues)
+ [

## 建立佇列
](#CreateQueue-create-queue)
+ [

## 取得佇列的 ARN
](#CreateQueue-get-arn)
+ [

## 完成程式碼
](#CreateQueue-complete-code)
+ [

## 其他考量
](#CreateQueue-additional)

## 顯示現有的佇列
<a name="CreateQueue-show-queues"></a>

下列程式碼片段顯示 SQS 用戶端區域中現有佇列的清單，以及每個佇列的屬性。

[本主題結尾](#CreateQueue-complete-code)的範例顯示此程式碼片段正在使用中。

```
    //
    // Method to show a list of the existing queues
    private static async Task ShowQueues(IAmazonSQS sqsClient)
    {
      ListQueuesResponse responseList = await sqsClient.ListQueuesAsync("");
      Console.WriteLine();
      foreach(string qUrl in responseList.QueueUrls)
      {
        // Get and show all attributes. Could also get a subset.
        await ShowAllAttributes(sqsClient, qUrl);
      }
    }

    //
    // Method to show all attributes of a queue
    private static async Task ShowAllAttributes(IAmazonSQS sqsClient, string qUrl)
    {
      var attributes = new List<string>{ QueueAttributeName.All };
      GetQueueAttributesResponse responseGetAtt =
        await sqsClient.GetQueueAttributesAsync(qUrl, attributes);
      Console.WriteLine($"Queue: {qUrl}");
      foreach(var att in responseGetAtt.Attributes)
        Console.WriteLine($"\t{att.Key}: {att.Value}");
    }
```

## 建立佇列
<a name="CreateQueue-create-queue"></a>

下列程式碼片段會建立佇列。程式碼片段包含使用無效字母佇列，但您的佇列不一定需要無效字母佇列。

[本主題結尾](#CreateQueue-complete-code)的範例顯示此程式碼片段正在使用中。

```
    //
    // Method to create a queue. Returns the queue URL.
    private static async Task<string> CreateQueue(
      IAmazonSQS sqsClient, string qName, string deadLetterQueueUrl=null,
      string maxReceiveCount=null, string receiveWaitTime=null)
    {
      var attrs = new Dictionary<string, string>();

      // If a dead-letter queue is given, create a message queue
      if(!string.IsNullOrEmpty(deadLetterQueueUrl))
      {
        attrs.Add(QueueAttributeName.ReceiveMessageWaitTimeSeconds, receiveWaitTime);
        attrs.Add(QueueAttributeName.RedrivePolicy,
          $"{{\"deadLetterTargetArn\":\"{await GetQueueArn(sqsClient, deadLetterQueueUrl)}\"," +
          $"\"maxReceiveCount\":\"{maxReceiveCount}\"}}");
        // Add other attributes for the message queue such as VisibilityTimeout
      }

      // If no dead-letter queue is given, create one of those instead
      //else
      //{
      //  // Add attributes for the dead-letter queue as needed
      //  attrs.Add();
      //}

      // Create the queue
      CreateQueueResponse responseCreate = await sqsClient.CreateQueueAsync(
          new CreateQueueRequest{QueueName = qName, Attributes = attrs});
      return responseCreate.QueueUrl;
    }
```

## 取得佇列的 ARN
<a name="CreateQueue-get-arn"></a>

下列程式碼片段會取得指定佇列 URL 所識別之佇列的 ARN。

[本主題結尾](#CreateQueue-complete-code)的範例顯示此程式碼片段正在使用中。

```
    //
    // Method to get the ARN of a queue
    private static async Task<string> GetQueueArn(IAmazonSQS sqsClient, string qUrl)
    {
      GetQueueAttributesResponse responseGetAtt = await sqsClient.GetQueueAttributesAsync(
        qUrl, new List<string>{QueueAttributeName.QueueArn});
      return responseGetAtt.QueueARN;
    }
```

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

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

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

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

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

  [AmazonSQSClient](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/SQS/TSQSClient.html) 類別

  類別 [QueueAttributeName](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/SQS/TQueueAttributeName.html)
+ 命名空間 [Amazon.SQS.Model](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/SQS/NSQSModel.html)

  類別 [CreateQueueRequest](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/SQS/TCreateQueueRequest.html)

  類別 [CreateQueueResponse](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/SQS/TCreateQueueResponse.html)

  類別 [GetQueueAttributesResponse](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/SQS/TGetQueueAttributesResponse.html)

  類別 [ListQueuesResponse](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/SQS/TListQueuesResponse.html)

### 程式碼
<a name="w2aac19c15c25c17c25b7b1"></a>

```
using System;
using System.Threading.Tasks;
using System.Collections.Generic;
using Amazon.SQS;
using Amazon.SQS.Model;

namespace SQSCreateQueue
{
  // = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
  // Class to create a queue
  class Program
  {
    private const string MaxReceiveCount = "10";
    private const string ReceiveMessageWaitTime = "2";
    private const int MaxArgs = 3;

    static async Task Main(string[] args)
    {
      // Parse the command line and show help if necessary
      var parsedArgs = CommandLine.Parse(args);
      if(parsedArgs.Count > MaxArgs)
        CommandLine.ErrorExit(
          "\nToo many command-line arguments.\nRun the command with no arguments to see help.");

      // Create the Amazon SQS client
      var sqsClient = new AmazonSQSClient();

      // In the case of no command-line arguments, just show help and the existing queues
      if(parsedArgs.Count == 0)
      {
        PrintHelp();
        Console.WriteLine("\nNo arguments specified.");
        Console.Write("Do you want to see a list of the existing queues? ((y) or n): ");
        string response = Console.ReadLine();
        if((string.IsNullOrEmpty(response)) || (response.ToLower() == "y"))
          await ShowQueues(sqsClient);
        return;
      }

      // Get the application arguments from the parsed list
      string queueName =
        CommandLine.GetArgument(parsedArgs, null, "-q", "--queue-name");
      string deadLetterQueueUrl =
        CommandLine.GetArgument(parsedArgs, null, "-d", "--dead-letter-queue");
      string maxReceiveCount =
        CommandLine.GetArgument(parsedArgs, MaxReceiveCount, "-m", "--max-receive-count");
      string receiveWaitTime =
        CommandLine.GetArgument(parsedArgs, ReceiveMessageWaitTime, "-w", "--wait-time");

      if(string.IsNullOrEmpty(queueName))
        CommandLine.ErrorExit(
          "\nYou must supply a queue name.\nRun the command with no arguments to see help.");

      // If a dead-letter queue wasn't given, create one
      if(string.IsNullOrEmpty(deadLetterQueueUrl))
      {
        Console.WriteLine("\nNo dead-letter queue was specified. Creating one...");
        deadLetterQueueUrl = await CreateQueue(sqsClient, queueName + "__dlq");
        Console.WriteLine($"Your new dead-letter queue:");
        await ShowAllAttributes(sqsClient, deadLetterQueueUrl);
      }

      // Create the message queue
      string messageQueueUrl = await CreateQueue(
        sqsClient, queueName, deadLetterQueueUrl, maxReceiveCount, receiveWaitTime);
      Console.WriteLine($"Your new message queue:");
      await ShowAllAttributes(sqsClient, messageQueueUrl);
    }


    //
    // Method to show a list of the existing queues
    private static async Task ShowQueues(IAmazonSQS sqsClient)
    {
      ListQueuesResponse responseList = await sqsClient.ListQueuesAsync("");
      Console.WriteLine();
      foreach(string qUrl in responseList.QueueUrls)
      {
        // Get and show all attributes. Could also get a subset.
        await ShowAllAttributes(sqsClient, qUrl);
      }
    }


    //
    // Method to create a queue. Returns the queue URL.
    private static async Task<string> CreateQueue(
      IAmazonSQS sqsClient, string qName, string deadLetterQueueUrl=null,
      string maxReceiveCount=null, string receiveWaitTime=null)
    {
      var attrs = new Dictionary<string, string>();

      // If a dead-letter queue is given, create a message queue
      if(!string.IsNullOrEmpty(deadLetterQueueUrl))
      {
        attrs.Add(QueueAttributeName.ReceiveMessageWaitTimeSeconds, receiveWaitTime);
        attrs.Add(QueueAttributeName.RedrivePolicy,
          $"{{\"deadLetterTargetArn\":\"{await GetQueueArn(sqsClient, deadLetterQueueUrl)}\"," +
          $"\"maxReceiveCount\":\"{maxReceiveCount}\"}}");
        // Add other attributes for the message queue such as VisibilityTimeout
      }

      // If no dead-letter queue is given, create one of those instead
      //else
      //{
      //  // Add attributes for the dead-letter queue as needed
      //  attrs.Add();
      //}

      // Create the queue
      CreateQueueResponse responseCreate = await sqsClient.CreateQueueAsync(
          new CreateQueueRequest{QueueName = qName, Attributes = attrs});
      return responseCreate.QueueUrl;
    }


    //
    // Method to get the ARN of a queue
    private static async Task<string> GetQueueArn(IAmazonSQS sqsClient, string qUrl)
    {
      GetQueueAttributesResponse responseGetAtt = await sqsClient.GetQueueAttributesAsync(
        qUrl, new List<string>{QueueAttributeName.QueueArn});
      return responseGetAtt.QueueARN;
    }


    //
    // Method to show all attributes of a queue
    private static async Task ShowAllAttributes(IAmazonSQS sqsClient, string qUrl)
    {
      var attributes = new List<string>{ QueueAttributeName.All };
      GetQueueAttributesResponse responseGetAtt =
        await sqsClient.GetQueueAttributesAsync(qUrl, attributes);
      Console.WriteLine($"Queue: {qUrl}");
      foreach(var att in responseGetAtt.Attributes)
        Console.WriteLine($"\t{att.Key}: {att.Value}");
    }


    //
    // Command-line help
    private static void PrintHelp()
    {
      Console.WriteLine(
      "\nUsage: SQSCreateQueue -q <queue-name> [-d <dead-letter-queue>]" +
        " [-m <max-receive-count>] [-w <wait-time>]" +
      "\n  -q, --queue-name: The name of the queue you want to create." +
      "\n  -d, --dead-letter-queue: The URL of an existing queue to be used as the dead-letter queue."+
      "\n      If this argument isn't supplied, a new dead-letter queue will be created." +
      "\n  -m, --max-receive-count: The value for maxReceiveCount in the RedrivePolicy of the queue." +
      $"\n      Default is {MaxReceiveCount}." +
      "\n  -w, --wait-time: The value for ReceiveMessageWaitTimeSeconds of the queue for long polling." +
      $"\n      Default is {ReceiveMessageWaitTime}.");
    }
  }


  // = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
  // Class that represents a command line on the console or terminal.
  // (This is the same for all examples. When you have seen it once, you can ignore it.)
  static class CommandLine
  {
    //
    // Method to parse a command line of the form: "--key value" or "-k value".
    //
    // Parameters:
    // - args: The command-line arguments passed into the application by the system.
    //
    // Returns:
    // A Dictionary with string Keys and Values.
    //
    // If a key is found without a matching value, Dictionary.Value is set to the key
    //  (including the dashes).
    // If a value is found without a matching key, Dictionary.Key is set to "--NoKeyN",
    //  where "N" represents sequential numbers.
    public static Dictionary<string,string> Parse(string[] args)
    {
      var parsedArgs = new Dictionary<string,string>();
      int i = 0, n = 0;
      while(i < args.Length)
      {
        // If the first argument in this iteration starts with a dash it's an option.
        if(args[i].StartsWith("-"))
        {
          var key = args[i++];
          var value = key;

          // Check to see if there's a value that goes with this option?
          if((i < args.Length) && (!args[i].StartsWith("-"))) value = args[i++];
          parsedArgs.Add(key, value);
        }

        // If the first argument in this iteration doesn't start with a dash, it's a value
        else
        {
          parsedArgs.Add("--NoKey" + n.ToString(), args[i++]);
          n++;
        }
      }

      return parsedArgs;
    }

    //
    // Method to get an argument from the parsed command-line arguments
    //
    // Parameters:
    // - parsedArgs: The Dictionary object returned from the Parse() method (shown above).
    // - defaultValue: The default string to return if the specified key isn't in parsedArgs.
    // - keys: An array of keys to look for in parsedArgs.
    public static string GetArgument(
      Dictionary<string,string> parsedArgs, string defaultReturn, params string[] keys)
    {
      string retval = null;
      foreach(var key in keys)
        if(parsedArgs.TryGetValue(key, out retval)) break;
      return retval ?? defaultReturn;
    }

    //
    // Method to exit the application with an error.
    public static void ErrorExit(string msg, int code=1)
    {
      Console.WriteLine("\nError");
      Console.WriteLine(msg);
      Environment.Exit(code);
    }
  }

}
```

## 其他考量
<a name="CreateQueue-additional"></a>
+ 您的佇列名稱必須由英數字元、連字號和底線組成。
+ 佇列名稱和佇列 URLs 區分大小寫
+ 如果您需要佇列 URL，但只有佇列名稱，請使用其中一種`AmazonSQSClient.GetQueueUrlAsync`方法。
+ 如需有關您可以設定之各種佇列屬性的資訊，請參閱《 [適用於 .NET 的 AWS SDK API 參考](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/)》中的 [CreateQueueRequest](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/SQS/TCreateQueueRequest.html) 或《[Amazon Simple Queue Service API 參考](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/)》中的 [SetQueueAttributes](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_SetQueueAttributes.html)。
+ 此範例會為您建立的佇列上的所有訊息指定長輪詢。這是使用 `ReceiveMessageWaitTimeSeconds` 屬性來完成。

  您也可以在呼叫 [AmazonSQSClient](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/SQS/TSQSClient.html) 類別`ReceiveMessageAsync`的方法期間指定長輪詢。如需詳細資訊，請參閱[接收 Amazon SQS 訊息](ReceiveMessage.md)。

  如需短輪詢與長輪詢的相關資訊，請參閱《*Amazon Simple Queue Service 開發人員指南*》中的[短輪詢和長輪詢](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-short-and-long-polling.html)。
+ 無效字母佇列是其他 （來源） 佇列可以為未成功處理的訊息設定目標的佇列。如需詳細資訊，請參閱[《Amazon Simple Queue Service 開發人員指南》中的 Amazon SQS 無效字母佇列](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-dead-letter-queues.html)。
+ 您也可以在 [Amazon SQS 主控台](https://console.aws.amazon.com/sqs)中查看佇列清單和此範例的結果。

# 更新 Amazon SQS 佇列
<a name="UpdateSqsQueue"></a>

此範例說明如何使用 適用於 .NET 的 AWS SDK 來更新 Amazon SQS 佇列。經過一些檢查後，應用程式會使用指定的值更新指定的屬性，然後顯示佇列的所有屬性。

如果命令列引數中只包含佇列 URL，則應用程式只會顯示佇列的所有屬性。

下列各節提供此範例的程式碼片段。之後會顯示[範例的完整程式碼](#UpdateSqsQueue-complete-code)，並可依原樣建置和執行。

**Topics**
+ [

## 顯示佇列屬性
](#UpdateSqsQueue-show-attributes)
+ [

## 驗證屬性名稱
](#UpdateSqsQueue-validate-attribute)
+ [

## 更新佇列屬性
](#UpdateSqsQueue-update-attribute)
+ [

## 完成程式碼
](#UpdateSqsQueue-complete-code)
+ [

## 其他考量
](#UpdateSqsQueue-additional)

## 顯示佇列屬性
<a name="UpdateSqsQueue-show-attributes"></a>

下列程式碼片段顯示指定佇列 URL 所識別之佇列的屬性。

[本主題結尾](#UpdateSqsQueue-complete-code)的範例顯示此程式碼片段正在使用中。

```
    //
    // Method to show all attributes of a queue
    private static async Task ShowAllAttributes(IAmazonSQS sqsClient, string qUrl)
    {
      GetQueueAttributesResponse responseGetAtt =
        await sqsClient.GetQueueAttributesAsync(qUrl,
          new List<string>{ QueueAttributeName.All });
      Console.WriteLine($"Queue: {qUrl}");
      foreach(var att in responseGetAtt.Attributes)
        Console.WriteLine($"\t{att.Key}: {att.Value}");
    }
```

## 驗證屬性名稱
<a name="UpdateSqsQueue-validate-attribute"></a>

下列程式碼片段會驗證要更新的屬性名稱。

[本主題結尾](#UpdateSqsQueue-complete-code)的範例顯示此程式碼片段正在使用中。

```
    //
    // Method to check the name of the attribute
    private static bool ValidAttribute(string attribute)
    {
      var attOk = false;
      var qAttNameType = typeof(QueueAttributeName);
      List<string> qAttNamefields = new List<string>();
      foreach(var field in qAttNameType.GetFields())
       qAttNamefields.Add(field.Name);
      foreach(var name in qAttNamefields)
        if(attribute == name) { attOk = true; break; }
      return attOk;
    }
```

## 更新佇列屬性
<a name="UpdateSqsQueue-update-attribute"></a>

下列程式碼片段會更新指定佇列 URL 所識別之佇列的屬性。

[本主題結尾](#UpdateSqsQueue-complete-code)的範例顯示此程式碼片段正在使用中。

```
    //
    // Method to update a queue attribute
    private static async Task UpdateAttribute(
      IAmazonSQS sqsClient, string qUrl, string attribute, string value)
    {
      await sqsClient.SetQueueAttributesAsync(qUrl,
        new Dictionary<string, string>{{attribute, value}});
    }
```

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

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

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

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

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

  [AmazonSQSClient](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/SQS/TSQSClient.html) 類別

  類別 [QueueAttributeName](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/SQS/TQueueAttributeName.html)
+ 命名空間 [Amazon.SQS.Model](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/SQS/NSQSModel.html)

  類別 [GetQueueAttributesResponse](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/SQS/TGetQueueAttributesResponse.html)

### 程式碼
<a name="w2aac19c15c25c19c25b7b1"></a>

```
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Amazon.SQS;
using Amazon.SQS.Model;

namespace SQSUpdateQueue
{
  // = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
  // Class to update a queue
  class Program
  {
    private const int MaxArgs = 3;
    private const int InvalidArgCount = 2;

    static async Task Main(string[] args)
    {
      // Parse the command line and show help if necessary
      var parsedArgs = CommandLine.Parse(args);
      if(parsedArgs.Count == 0)
      {
        PrintHelp();
        return;
      }
      if((parsedArgs.Count > MaxArgs) || (parsedArgs.Count == InvalidArgCount))
        CommandLine.ErrorExit("\nThe number of command-line arguments is incorrect." +
          "\nRun the command with no arguments to see help.");

      // Get the application arguments from the parsed list
      var qUrl = CommandLine.GetArgument(parsedArgs, null, "-q");
      var attribute = CommandLine.GetArgument(parsedArgs, null, "-a");
      var value = CommandLine.GetArgument(parsedArgs, null, "-v", "--value");

      if(string.IsNullOrEmpty(qUrl))
        CommandLine.ErrorExit("\nYou must supply at least a queue URL." +
          "\nRun the command with no arguments to see help.");

      // Create the Amazon SQS client
      var sqsClient = new AmazonSQSClient();

      // In the case of one command-line argument, just show the attributes for the queue
      if(parsedArgs.Count == 1)
        await ShowAllAttributes(sqsClient, qUrl);

      // Otherwise, attempt to update the given queue attribute with the given value
      else
      {
        // Check to see if the attribute is valid
        if(ValidAttribute(attribute))
        {
          // Perform the update and then show all the attributes of the queue
          await UpdateAttribute(sqsClient, qUrl, attribute, value);
          await ShowAllAttributes(sqsClient, qUrl);
        }
        else
        {
          Console.WriteLine($"\nThe given attribute name, {attribute}, isn't valid.");
        }
      }
    }


    //
    // Method to show all attributes of a queue
    private static async Task ShowAllAttributes(IAmazonSQS sqsClient, string qUrl)
    {
      GetQueueAttributesResponse responseGetAtt =
        await sqsClient.GetQueueAttributesAsync(qUrl,
          new List<string>{ QueueAttributeName.All });
      Console.WriteLine($"Queue: {qUrl}");
      foreach(var att in responseGetAtt.Attributes)
        Console.WriteLine($"\t{att.Key}: {att.Value}");
    }


    //
    // Method to check the name of the attribute
    private static bool ValidAttribute(string attribute)
    {
      var attOk = false;
      var qAttNameType = typeof(QueueAttributeName);
      List<string> qAttNamefields = new List<string>();
      foreach(var field in qAttNameType.GetFields())
       qAttNamefields.Add(field.Name);
      foreach(var name in qAttNamefields)
        if(attribute == name) { attOk = true; break; }
      return attOk;
    }


    //
    // Method to update a queue attribute
    private static async Task UpdateAttribute(
      IAmazonSQS sqsClient, string qUrl, string attribute, string value)
    {
      await sqsClient.SetQueueAttributesAsync(qUrl,
        new Dictionary<string, string>{{attribute, value}});
    }


    //
    // Command-line help
    private static void PrintHelp()
    {
      Console.WriteLine("\nUsage: SQSUpdateQueue -q queue_url [-a attribute -v value]");
      Console.WriteLine("  -q: The URL of the queue you want to update.");
      Console.WriteLine("  -a: The name of the attribute to update.");
      Console.WriteLine("  -v, --value: The value to assign to the attribute.");
    }
  }


  // = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
  // Class that represents a command line on the console or terminal.
  // (This is the same for all examples. When you have seen it once, you can ignore it.)
  static class CommandLine
  {
    //
    // Method to parse a command line of the form: "--key value" or "-k value".
    //
    // Parameters:
    // - args: The command-line arguments passed into the application by the system.
    //
    // Returns:
    // A Dictionary with string Keys and Values.
    //
    // If a key is found without a matching value, Dictionary.Value is set to the key
    //  (including the dashes).
    // If a value is found without a matching key, Dictionary.Key is set to "--NoKeyN",
    //  where "N" represents sequential numbers.
    public static Dictionary<string,string> Parse(string[] args)
    {
      var parsedArgs = new Dictionary<string,string>();
      int i = 0, n = 0;
      while(i < args.Length)
      {
        // If the first argument in this iteration starts with a dash it's an option.
        if(args[i].StartsWith("-"))
        {
          var key = args[i++];
          var value = key;

          // Check to see if there's a value that goes with this option?
          if((i < args.Length) && (!args[i].StartsWith("-"))) value = args[i++];
          parsedArgs.Add(key, value);
        }

        // If the first argument in this iteration doesn't start with a dash, it's a value
        else
        {
          parsedArgs.Add("--NoKey" + n.ToString(), args[i++]);
          n++;
        }
      }

      return parsedArgs;
    }

    //
    // Method to get an argument from the parsed command-line arguments
    //
    // Parameters:
    // - parsedArgs: The Dictionary object returned from the Parse() method (shown above).
    // - defaultValue: The default string to return if the specified key isn't in parsedArgs.
    // - keys: An array of keys to look for in parsedArgs.
    public static string GetArgument(
      Dictionary<string,string> parsedArgs, string defaultReturn, params string[] keys)
    {
      string retval = null;
      foreach(var key in keys)
        if(parsedArgs.TryGetValue(key, out retval)) break;
      return retval ?? defaultReturn;
    }

    //
    // Method to exit the application with an error.
    public static void ErrorExit(string msg, int code=1)
    {
      Console.WriteLine("\nError");
      Console.WriteLine(msg);
      Environment.Exit(code);
    }
  }

}
```

## 其他考量
<a name="UpdateSqsQueue-additional"></a>
+ 若要更新 `RedrivePolicy` 屬性，您必須根據您的作業系統，引用整個值並逸出鍵/值對的引號。

  例如，在 Windows 上， 值的建構方式類似如下：

  ```
  "{\"deadLetterTargetArn\":\"DEAD_LETTER-QUEUE-ARN\",\"maxReceiveCount\":\"10\"}"
  ```

# 刪除 Amazon SQS 佇列
<a name="DeleteSqsQueue"></a>

此範例說明如何使用 適用於 .NET 的 AWS SDK 刪除 Amazon SQS 佇列。應用程式會刪除佇列、等待一段指定的時間讓佇列消失，然後顯示剩餘的佇列清單。

如果您未提供任何命令列引數，應用程式只會顯示現有佇列的清單。

下列各節提供此範例的程式碼片段。之後會顯示[範例的完整程式碼](#DeleteSqsQueue-complete-code)，並可依原樣建置和執行。

**Topics**
+ [

## 刪除佇列
](#DeleteSqsQueue-delete-queue)
+ [

## 等待佇列消失
](#DeleteSqsQueue-wait)
+ [

## 顯示現有佇列的清單
](#DeleteSqsQueue-list-queues)
+ [

## 完成程式碼
](#DeleteSqsQueue-complete-code)
+ [

## 其他考量
](#DeleteSqsQueue-additional)

## 刪除佇列
<a name="DeleteSqsQueue-delete-queue"></a>

下列程式碼片段會刪除指定佇列 URL 所識別的佇列。

[本主題結尾](#DeleteSqsQueue-complete-code)的範例顯示此程式碼片段正在使用中。

```
    //
    // Method to delete an SQS queue
    private static async Task DeleteQueue(IAmazonSQS sqsClient, string qUrl)
    {
      Console.WriteLine($"Deleting queue {qUrl}...");
      await sqsClient.DeleteQueueAsync(qUrl);
      Console.WriteLine($"Queue {qUrl} has been deleted.");
    }
```

## 等待佇列消失
<a name="DeleteSqsQueue-wait"></a>

下列程式碼片段會等待刪除程序完成，這可能需要 60 秒。

[本主題結尾](#DeleteSqsQueue-complete-code)的範例顯示此程式碼片段正在使用中。

```
    //
    // Method to wait up to a given number of seconds
    private static async Task Wait(
      IAmazonSQS sqsClient, int numSeconds, string qUrl)
    {
      Console.WriteLine($"Waiting for up to {numSeconds} seconds.");
      Console.WriteLine("Press any key to stop waiting. (Response might be slightly delayed.)");
      for(int i=0; i<numSeconds; i++)
      {
        Console.Write(".");
        Thread.Sleep(1000);
        if(Console.KeyAvailable) break;

        // Check to see if the queue is gone yet
        var found = false;
        ListQueuesResponse responseList = await sqsClient.ListQueuesAsync("");
        foreach(var url in responseList.QueueUrls)
        {
          if(url == qUrl)
          {
            found = true;
            break;
          }
        }
        if(!found) break;
      }
    }
```

## 顯示現有佇列的清單
<a name="DeleteSqsQueue-list-queues"></a>

下列程式碼片段顯示 SQS 用戶端區域中現有佇列的清單。

[本主題結尾](#DeleteSqsQueue-complete-code)的範例顯示此程式碼片段正在使用中。

```
    //
    // Method to show a list of the existing queues
    private static async Task ListQueues(IAmazonSQS sqsClient)
    {
      ListQueuesResponse responseList = await sqsClient.ListQueuesAsync("");
      Console.WriteLine("\nList of queues:");
      foreach(var qUrl in responseList.QueueUrls)
        Console.WriteLine($"- {qUrl}");
    }
```

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

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

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

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

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

  [AmazonSQSClient](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/SQS/TSQSClient.html) 類別
+ 命名空間 [Amazon.SQS.Model](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/SQS/NSQSModel.html)

  類別 [ListQueuesResponse](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/SQS/TListQueuesResponse.html)

### 程式碼
<a name="w2aac19c15c25c21c25b7b1"></a>

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

namespace SQSDeleteQueue
{
  // = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
  // Class to update a queue
  class Program
  {
    private const int TimeToWait = 60;

    static async Task Main(string[] args)
    {
      // Create the Amazon SQS client
      var sqsClient = new AmazonSQSClient();

      // If no command-line arguments, just show a list of the queues
      if(args.Length == 0)
      {
        Console.WriteLine("\nUsage: SQSCreateQueue queue_url");
        Console.WriteLine("   queue_url - The URL of the queue you want to delete.");
        Console.WriteLine("\nNo arguments specified.");
        Console.Write("Do you want to see a list of the existing queues? ((y) or n): ");
        var response = Console.ReadLine();
        if((string.IsNullOrEmpty(response)) || (response.ToLower() == "y"))
          await ListQueues(sqsClient);
        return;
      }

      // If given a queue URL, delete that queue
      if(args[0].StartsWith("https://sqs."))
      {
        // Delete the queue
        await DeleteQueue(sqsClient, args[0]);
        // Wait for a little while because it takes a while for the queue to disappear
        await Wait(sqsClient, TimeToWait, args[0]);
        // Show a list of the remaining queues
        await ListQueues(sqsClient);
      }
      else
      {
        Console.WriteLine("The command-line argument isn't a queue URL:");
        Console.WriteLine($"{args[0]}");
      }
    }


    //
    // Method to delete an SQS queue
    private static async Task DeleteQueue(IAmazonSQS sqsClient, string qUrl)
    {
      Console.WriteLine($"Deleting queue {qUrl}...");
      await sqsClient.DeleteQueueAsync(qUrl);
      Console.WriteLine($"Queue {qUrl} has been deleted.");
    }


    //
    // Method to wait up to a given number of seconds
    private static async Task Wait(
      IAmazonSQS sqsClient, int numSeconds, string qUrl)
    {
      Console.WriteLine($"Waiting for up to {numSeconds} seconds.");
      Console.WriteLine("Press any key to stop waiting. (Response might be slightly delayed.)");
      for(int i=0; i<numSeconds; i++)
      {
        Console.Write(".");
        Thread.Sleep(1000);
        if(Console.KeyAvailable) break;

        // Check to see if the queue is gone yet
        var found = false;
        ListQueuesResponse responseList = await sqsClient.ListQueuesAsync("");
        foreach(var url in responseList.QueueUrls)
        {
          if(url == qUrl)
          {
            found = true;
            break;
          }
        }
        if(!found) break;
      }
    }


    //
    // Method to show a list of the existing queues
    private static async Task ListQueues(IAmazonSQS sqsClient)
    {
      ListQueuesResponse responseList = await sqsClient.ListQueuesAsync("");
      Console.WriteLine("\nList of queues:");
      foreach(var qUrl in responseList.QueueUrls)
        Console.WriteLine($"- {qUrl}");
    }
  }
}
```

## 其他考量
<a name="DeleteSqsQueue-additional"></a>
+ `DeleteQueueAsync` API 呼叫不會檢查您要刪除的佇列是否用作無效字母佇列。更複雜的程序可以檢查此項目。
+ 您也可以在 [Amazon SQS 主控台](https://console.aws.amazon.com/sqs)中查看佇列清單和此範例的結果。

# 傳送 Amazon SQS 訊息
<a name="SendMessage"></a>

此範例說明如何使用 適用於 .NET 的 AWS SDK 將訊息傳送至 Amazon SQS 佇列，您可以透過[程式設計方式](CreateQueue.md)或使用 [Amazon SQS 主控台](https://console.aws.amazon.com/sqs)建立該佇列。應用程式會將單一訊息傳送至佇列，然後傳送一批訊息。然後，應用程式會等待使用者輸入，這可以是要傳送至佇列的其他訊息或結束應用程式的請求。

此範例和[接收訊息的下一個範例](ReceiveMessage.md)可以一起使用，以查看 Amazon SQS 中的訊息流程。

下列各節提供此範例的程式碼片段。之後會顯示[範例的完整程式碼](#SendMessage-complete-code)，並可依原樣建置和執行。

**Topics**
+ [

## 傳送訊息
](#SendMessage-send-message)
+ [

## 傳送一批訊息
](#SendMessage-send-batch)
+ [

## 從佇列刪除所有訊息
](#SendMessage-purge-messages)
+ [

## 完成程式碼
](#SendMessage-complete-code)
+ [

## 其他考量
](#SendMessage-additional)

## 傳送訊息
<a name="SendMessage-send-message"></a>

下列程式碼片段會傳送訊息至指定佇列 URL 所識別的佇列。

[本主題結尾](#SendMessage-complete-code)的範例顯示此程式碼片段正在使用中。

```
    //
    // Method to put a message on a queue
    // Could be expanded to include message attributes, etc., in a SendMessageRequest
    private static async Task SendMessage(
      IAmazonSQS sqsClient, string qUrl, string messageBody)
    {
      SendMessageResponse responseSendMsg =
        await sqsClient.SendMessageAsync(qUrl, messageBody);
      Console.WriteLine($"Message added to queue\n  {qUrl}");
      Console.WriteLine($"HttpStatusCode: {responseSendMsg.HttpStatusCode}");
    }
```

## 傳送一批訊息
<a name="SendMessage-send-batch"></a>

下列程式碼片段會將一批訊息傳送至指定佇列 URL 所識別的佇列。

[本主題結尾](#SendMessage-complete-code)的範例顯示此程式碼片段正在使用中。

```
    //
    // Method to put a batch of messages on a queue
    // Could be expanded to include message attributes, etc.,
    // in the SendMessageBatchRequestEntry objects
    private static async Task SendMessageBatch(
      IAmazonSQS sqsClient, string qUrl, List<SendMessageBatchRequestEntry> messages)
    {
      Console.WriteLine($"\nSending a batch of messages to queue\n  {qUrl}");
      SendMessageBatchResponse responseSendBatch =
        await sqsClient.SendMessageBatchAsync(qUrl, messages);
      // Could test responseSendBatch.Failed here
      foreach(SendMessageBatchResultEntry entry in responseSendBatch.Successful)
        Console.WriteLine($"Message {entry.Id} successfully queued.");
    }
```

## 從佇列刪除所有訊息
<a name="SendMessage-purge-messages"></a>

下列程式碼片段會從指定佇列 URL 識別的佇列中刪除所有訊息。這也稱為*清除佇列*。

[本主題結尾](#SendMessage-complete-code)的範例顯示此程式碼片段正在使用中。

```
    //
    // Method to delete all messages from the queue
    private static async Task DeleteAllMessages(IAmazonSQS sqsClient, string qUrl)
    {
      Console.WriteLine($"\nPurging messages from queue\n  {qUrl}...");
      PurgeQueueResponse responsePurge = await sqsClient.PurgeQueueAsync(qUrl);
      Console.WriteLine($"HttpStatusCode: {responsePurge.HttpStatusCode}");
    }
```

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

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

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

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

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

  [AmazonSQSClient](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/SQS/TSQSClient.html) 類別
+ 命名空間 [Amazon.SQS.Model](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/SQS/NSQSModel.html)

  類別 [PurgeQueueResponse](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/SQS/TPurgeQueueResponse.html)

  類別 [SendMessageBatchResponse](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/SQS/TSendMessageBatchResponse.html)

  類別 [SendMessageResponse](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/SQS/TSendMessageResponse.html)

  類別 [SendMessageBatchRequestEntry](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/SQS/TSendMessageBatchRequestEntry.html)

  類別 [SendMessageBatchResultEntry](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/SQS/TSendMessageBatchResultEntry.html)

### 程式碼
<a name="w2aac19c15c25c23c25b7b1"></a>

```
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Amazon.SQS;
using Amazon.SQS.Model;

namespace SQSSendMessages
{
  // = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
  // Class to send messages to a queue
  class Program
  {
    // Some example messages to send to the queue
    private const string JsonMessage = "{\"product\":[{\"name\":\"Product A\",\"price\": \"32\"},{\"name\": \"Product B\",\"price\": \"27\"}]}";
    private const string XmlMessage = "<products><product name=\"Product A\" price=\"32\" /><product name=\"Product B\" price=\"27\" /></products>";
    private const string CustomMessage = "||product|Product A|32||product|Product B|27||";
    private const string TextMessage = "Just a plain text message.";

    static async Task Main(string[] args)
    {
      // Do some checks on the command-line
      if(args.Length == 0)
      {
        Console.WriteLine("\nUsage: SQSSendMessages queue_url");
        Console.WriteLine("   queue_url - The URL of an existing SQS queue.");
        return;
      }
      if(!args[0].StartsWith("https://sqs."))
      {
        Console.WriteLine("\nThe command-line argument isn't a queue URL:");
        Console.WriteLine($"{args[0]}");
        return;
      }

      // Create the Amazon SQS client
      var sqsClient = new AmazonSQSClient();

      // (could verify that the queue exists)
      // Send some example messages to the given queue
      // A single message
      await SendMessage(sqsClient, args[0], JsonMessage);

      // A batch of messages
      var batchMessages = new List<SendMessageBatchRequestEntry>{
        new SendMessageBatchRequestEntry("xmlMsg", XmlMessage),
        new SendMessageBatchRequestEntry("customeMsg", CustomMessage),
        new SendMessageBatchRequestEntry("textMsg", TextMessage)};
      await SendMessageBatch(sqsClient, args[0], batchMessages);

      // Let the user send their own messages or quit
      await InteractWithUser(sqsClient, args[0]);

      // Delete all messages that are still in the queue
      await DeleteAllMessages(sqsClient, args[0]);
    }


    //
    // Method to put a message on a queue
    // Could be expanded to include message attributes, etc., in a SendMessageRequest
    private static async Task SendMessage(
      IAmazonSQS sqsClient, string qUrl, string messageBody)
    {
      SendMessageResponse responseSendMsg =
        await sqsClient.SendMessageAsync(qUrl, messageBody);
      Console.WriteLine($"Message added to queue\n  {qUrl}");
      Console.WriteLine($"HttpStatusCode: {responseSendMsg.HttpStatusCode}");
    }


    //
    // Method to put a batch of messages on a queue
    // Could be expanded to include message attributes, etc.,
    // in the SendMessageBatchRequestEntry objects
    private static async Task SendMessageBatch(
      IAmazonSQS sqsClient, string qUrl, List<SendMessageBatchRequestEntry> messages)
    {
      Console.WriteLine($"\nSending a batch of messages to queue\n  {qUrl}");
      SendMessageBatchResponse responseSendBatch =
        await sqsClient.SendMessageBatchAsync(qUrl, messages);
      // Could test responseSendBatch.Failed here
      foreach(SendMessageBatchResultEntry entry in responseSendBatch.Successful)
        Console.WriteLine($"Message {entry.Id} successfully queued.");
    }


    //
    // Method to get input from the user
    // They can provide messages to put in the queue or exit the application
    private static async Task InteractWithUser(IAmazonSQS sqsClient, string qUrl)
    {
      string response;
      while (true)
      {
        // Get the user's input
        Console.WriteLine("\nType a message for the queue or \"exit\" to quit:");
        response = Console.ReadLine();
        if(response.ToLower() == "exit") break;

        // Put the user's message in the queue
        await SendMessage(sqsClient, qUrl, response);
      }
    }


    //
    // Method to delete all messages from the queue
    private static async Task DeleteAllMessages(IAmazonSQS sqsClient, string qUrl)
    {
      Console.WriteLine($"\nPurging messages from queue\n  {qUrl}...");
      PurgeQueueResponse responsePurge = await sqsClient.PurgeQueueAsync(qUrl);
      Console.WriteLine($"HttpStatusCode: {responsePurge.HttpStatusCode}");
    }
  }
}
```

## 其他考量
<a name="SendMessage-additional"></a>
+ 如需有關訊息各種限制的資訊，包括允許的字元，請參閱《[Amazon Simple Queue Service 開發人員指南](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/)》中的[訊息相關配額](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-quotas.html#quotas-messages)。
+ 訊息會保留在佇列中，直到刪除或清除佇列為止。當應用程式收到訊息時，即使佇列中仍有訊息，它也不會出現在佇列中。如需可見性逾時的詳細資訊，請參閱 [Amazon SQS 可見性逾時](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/AboutVT.html)。
+ 除了訊息內文之外，您也可以將屬性新增至訊息。如需詳細資訊，請參閱[訊息中繼資料](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-message-metadata.html)。

# 接收 Amazon SQS 訊息
<a name="ReceiveMessage"></a>

此範例說明如何使用 從 Amazon SQS 佇列 適用於 .NET 的 AWS SDK 接收訊息，您可以透過[程式設計方式](CreateQueue.md)或使用 [Amazon SQS 主控台](https://console.aws.amazon.com/sqs)建立。應用程式會從佇列讀取單一訊息、處理訊息 （在此情況下， 會在主控台上顯示訊息內文），然後從佇列刪除訊息。應用程式會重複這些步驟，直到使用者在鍵盤上輸入金鑰為止。

此範例和[先前有關傳送訊息的範例](SendMessage.md)可以一起使用，以查看 Amazon SQS 中的訊息流程。

下列各節提供此範例的程式碼片段。之後會顯示[範例的完整程式碼](#ReceiveMessage-complete-code)，並可依原樣建置和執行。

**Topics**
+ [

## 接收訊息
](#ReceiveMessage-receive)
+ [

## 刪除訊息
](#ReceiveMessage-delete)
+ [

## 完成程式碼
](#ReceiveMessage-complete-code)
+ [

## 其他考量
](#ReceiveMessage-additional)

## 接收訊息
<a name="ReceiveMessage-receive"></a>

下列程式碼片段會從指定佇列 URL 識別的佇列接收訊息。

[本主題結尾](#ReceiveMessage-complete-code)的範例顯示此程式碼片段正在使用中。

```
    //
    // Method to read a message from the given queue
    // In this example, it gets one message at a time
    private static async Task<ReceiveMessageResponse> GetMessage(
      IAmazonSQS sqsClient, string qUrl, int waitTime=0)
    {
      return await sqsClient.ReceiveMessageAsync(new ReceiveMessageRequest{
        QueueUrl=qUrl,
        MaxNumberOfMessages=MaxMessages,
        WaitTimeSeconds=waitTime
        // (Could also request attributes, set visibility timeout, etc.)
      });
    }
```

## 刪除訊息
<a name="ReceiveMessage-delete"></a>

下列程式碼片段會從指定佇列 URL 識別的佇列中刪除訊息。

[本主題結尾](#ReceiveMessage-complete-code)的範例顯示此程式碼片段正在使用中。

```
    //
    // Method to delete a message from a queue
    private static async Task DeleteMessage(
      IAmazonSQS sqsClient, Message message, string qUrl)
    {
      Console.WriteLine($"\nDeleting message {message.MessageId} from queue...");
      await sqsClient.DeleteMessageAsync(qUrl, message.ReceiptHandle);
    }
```

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

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

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

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

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

  [AmazonSQSClient](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/SQS/TSQSClient.html) 類別
+ 命名空間 [Amazon.SQS.Model](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/SQS/NSQSModel.html)

  類別 [ReceiveMessageRequest](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/SQS/TReceiveMessageRequest.html)

  類別 [ReceiveMessageResponse](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/SQS/TReceiveMessageResponse.html)

### 程式碼
<a name="w2aac19c15c25c25c21b7b1"></a>

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

namespace SQSReceiveMessages
{
  class Program
  {
    private const int MaxMessages = 1;
    private const int WaitTime = 2;
    static async Task Main(string[] args)
    {
      // Do some checks on the command-line
      if(args.Length == 0)
      {
        Console.WriteLine("\nUsage: SQSReceiveMessages queue_url");
        Console.WriteLine("   queue_url - The URL of an existing SQS queue.");
        return;
      }
      if(!args[0].StartsWith("https://sqs."))
      {
        Console.WriteLine("\nThe command-line argument isn't a queue URL:");
        Console.WriteLine($"{args[0]}");
        return;
      }

      // Create the Amazon SQS client
      var sqsClient = new AmazonSQSClient();

      // (could verify that the queue exists)
      // Read messages from the queue and perform appropriate actions
      Console.WriteLine($"Reading messages from queue\n  {args[0]}");
      Console.WriteLine("Press any key to stop. (Response might be slightly delayed.)");
      do
      {
        var msg = await GetMessage(sqsClient, args[0], WaitTime);
        if(msg.Messages.Count != 0)
        {
          if(ProcessMessage(msg.Messages[0]))
            await DeleteMessage(sqsClient, msg.Messages[0], args[0]);
        }
      } while(!Console.KeyAvailable);
    }


    //
    // Method to read a message from the given queue
    // In this example, it gets one message at a time
    private static async Task<ReceiveMessageResponse> GetMessage(
      IAmazonSQS sqsClient, string qUrl, int waitTime=0)
    {
      return await sqsClient.ReceiveMessageAsync(new ReceiveMessageRequest{
        QueueUrl=qUrl,
        MaxNumberOfMessages=MaxMessages,
        WaitTimeSeconds=waitTime
        // (Could also request attributes, set visibility timeout, etc.)
      });
    }


    //
    // Method to process a message
    // In this example, it simply prints the message
    private static bool ProcessMessage(Message message)
    {
      Console.WriteLine($"\nMessage body of {message.MessageId}:");
      Console.WriteLine($"{message.Body}");
      return true;
    }


    //
    // Method to delete a message from a queue
    private static async Task DeleteMessage(
      IAmazonSQS sqsClient, Message message, string qUrl)
    {
      Console.WriteLine($"\nDeleting message {message.MessageId} from queue...");
      await sqsClient.DeleteMessageAsync(qUrl, message.ReceiptHandle);
    }
  }
}
```

## 其他考量
<a name="ReceiveMessage-additional"></a>
+ 若要指定長輪詢，此範例會針對 `ReceiveMessageAsync`方法的每個呼叫使用 `WaitTimeSeconds` 屬性。

  您也可以在[建立](CreateQueue.md)或[更新](UpdateSqsQueue.md)佇列時使用 `ReceiveMessageWaitTimeSeconds` 屬性，為佇列上的所有訊息指定長輪詢。

  如需短輪詢與長輪詢的相關資訊，請參閱《*Amazon Simple Queue Service 開發人員指南*》中的[短輪詢和長輪詢](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-short-and-long-polling.html)。
+ 在訊息處理期間，您可以使用接收控點來變更訊息可見性逾時。如需如何執行此操作的詳細資訊，請參閱 [AmazonSQSClient](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/SQS/TSQSClient.html) 類別`ChangeMessageVisibilityAsync`的方法。
+ 無論可見性逾時設定為何，無條件呼叫 `DeleteMessageAsync`方法都會從佇列中移除訊息。

# 使用 AWS Lambda 進行運算服務
<a name="aws-lambda"></a>

 適用於 .NET 的 AWS SDK 支援 AWS Lambda，可讓您在不佈建或管理伺服器的情況下執行程式碼。如需詳細資訊，請參閱 [AWS Lambda 產品頁面](https://aws.amazon.com/lambda/)和 [AWS Lambda 開發人員指南](https://docs.aws.amazon.com/lambda/latest/dg/)，特別是[使用 C\$1](https://docs.aws.amazon.com/lambda/latest/dg/lambda-csharp.html) 一節。

## API
<a name="w2aac19c17b5"></a>

 適用於 .NET 的 AWS SDK 提供 APIs AWS Lambda。APIs 可讓您使用[函數](https://docs.aws.amazon.com/lambda/latest/dg/gettingstarted-concepts.html#gettingstarted-concepts-function)、[觸發](https://docs.aws.amazon.com/lambda/latest/dg/gettingstarted-concepts.html#gettingstarted-concepts-trigger)條件和[事件](https://docs.aws.amazon.com/lambda/latest/dg/gettingstarted-concepts.html#gettingstarted-concepts-event)等 Lambda 功能。若要檢視完整的 APIs 集，請參閱 [適用於 .NET 的 AWS SDK API 參考](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/)中的 [Lambda](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/Lambda/NLambda.html)。

Lambda APIs 由 [NuGet 套件](https://www.nuget.org/packages?page=2&q=aws%20lambda&sortBy=relevance)提供。

## 先決條件
<a name="w2aac19c17b7"></a>

開始之前，請確定您已[設定環境和專案](net-dg-config.md)。也請檢閱 中的資訊[開發套件功能](net-dg-sdk-features.md)。

## 其他資訊
<a name="w2aac19c17b9"></a>

如需 AWS Lambda 透過 [ AWS 與 .NET Acover 整合](aspire-integrations.md) .NET Aspire 使用 進行開發的資訊，請參閱 。

## 主題
<a name="w2aac19c17c11"></a>

**Topics**
+ [

## API
](#w2aac19c17b5)
+ [

## 先決條件
](#w2aac19c17b7)
+ [

## 其他資訊
](#w2aac19c17b9)
+ [

## 主題
](#w2aac19c17c11)
+ [Lambda 註釋](aws-lambda-annotations.md)

# 使用註釋撰寫 AWS Lambda 函數
<a name="aws-lambda-annotations"></a>

撰寫 Lambda 函數時，有時需要撰寫大量處理常式程式碼和更新 AWS CloudFormation 範本，以及其他任務。Lambda Annotations 是一種架構，可協助減輕 .NET 6 Lambda 函數的這些負擔，因此讓編寫 Lambda 的體驗在 C\$1 中更自然。

使用 Lambda 註釋架構的好處範例是，請考慮以下程式碼片段，這些程式碼片段會新增兩個數字。

**不含 Lambda 註釋**

```
public class Functions
{
    public APIGatewayProxyResponse LambdaMathPlus(APIGatewayProxyRequest request, ILambdaContext context)
    {
        if (!request.PathParameters.TryGetValue("x", out var xs))
        {
            return new APIGatewayProxyResponse
            {
                StatusCode = (int)HttpStatusCode.BadRequest
            };
        }
        if (!request.PathParameters.TryGetValue("y", out var ys))
        {
            return new APIGatewayProxyResponse
            {
                StatusCode = (int)HttpStatusCode.BadRequest
            };
        }

        var x = int.Parse(xs);
        var y = int.Parse(ys);

        return new APIGatewayProxyResponse
        {
            StatusCode = (int)HttpStatusCode.OK,
            Body = (x + y).ToString(),
            Headers = new Dictionary<string, string> { { "Content-Type", "text/plain" } }
        };
    } 
}
```

**使用 Lambda 註釋**

```
public class Functions
{
    [LambdaFunction]
    [RestApi("/plus/{x}/{y}")]
    public int Plus(int x, int y)
    {
        return x + y;
    }
}
```

如範例所示，Lambda Annotations 可以消除對特定沸騰板程式碼的需求。

如需如何使用架構的詳細資訊以及其他資訊，請參閱下列資源：
+ 有關 Lambda 註釋APIs 和屬性的文件的 [GitHub README](https://github.com/aws/aws-lambda-dotnet/blob/master/Libraries/src/Amazon.Lambda.Annotations/README.md)。
+ Lambda 註釋的 [部落格文章](https://aws.amazon.com/blogs/developer/net-lambda-annotations-framework/)。
+ [https://www.nuget.org/packages/Amazon.Lambda.Annotations](https://www.nuget.org/packages/Amazon.Lambda.Annotations) NuGet 套件。
+ GitHub 上的[相片資產管理專案](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/dotnetv3/cross-service/PhotoAssetManager)。具體而言，請參閱專案 [README](https://github.com/awsdocs/aws-doc-sdk-examples/blob/main/dotnetv3/cross-service/PhotoAssetManager/README.md) 中的 [PamApiAnnotations](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/dotnetv3/cross-service/PhotoAssetManager/PamApiAnnotations) 資料夾和 Lambda Annotations 參考。

# 的高階程式庫和架構 適用於 .NET 的 AWS SDK
<a name="high-level-libraries"></a>

下列各節包含不屬於核心 SDK 功能之高階程式庫和架構的相關資訊。這些程式庫和架構使用核心 SDK 功能來建立可簡化特定任務的功能。

如果您是初次使用 適用於 .NET 的 AWS SDK，建議您先查看[快速導覽](quick-start.md)主題。它為您提供 SDK 的簡介。

開始之前，請確定您已[設定環境和專案](net-dg-config.md)。也請檢閱 中的資訊[開發套件功能](net-dg-sdk-features.md)。

**Topics**
+ [訊息處理架構](msg-proc-fw.md)
+ [AWS 與 .NET Acover 整合](aspire-integrations.md)

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

適用於 .NET AWS 的訊息處理架構是一種 AWS原生架構，可簡化開發使用 Amazon Simple Queue Service (SQS)、Amazon Simple Notification Service (SNS) 和 Amazon EventBridge 等 AWS 服務的 .NET 訊息處理應用程式。此架構可減少開發人員需要撰寫的樣板程式碼數量，讓您在發佈和使用訊息時專注於商業邏輯。如需架構如何簡化開發的詳細資訊，請參閱部落格文章[介紹適用於 .NET AWS 的訊息處理架構 （預覽）](https://aws.amazon.com/blogs/developer/introducing-the-aws-message-processing-framework-for-net-preview/)。其中第一部分提供示範，顯示使用低階 API 呼叫和使用架構之間的差異。

訊息處理架構支援下列活動和功能：
+ 傳送訊息至 SQS 並將事件發佈至 SNS 和 EventBridge。
+ 使用長時間執行的輪詢器接收和處理來自 SQS 的訊息，這通常用於背景服務。這包括在處理訊息時管理可見性逾時，以防止其他用戶端處理它。
+ 在 AWS Lambda 函數中處理訊息。
+ FIFO first-in-first-out) SQS 佇列和 SNS 主題。
+ 用於記錄的 OpenTelemetry。

如需這些活動和功能的詳細資訊，請參閱[部落格文章](https://aws.amazon.com/blogs/developer/introducing-the-aws-message-processing-framework-for-net-preview/)的功能****一節和下列主題。

開始之前，請確定您已[設定環境和專案](net-dg-config.md)。也請檢閱 中的資訊[開發套件功能](net-dg-sdk-features.md)。

**其他資源**
+ [NuGet.org](https://www.nuget.org/) 上的[https://www.nuget.org/packages/AWS.Messaging/](https://www.nuget.org/packages/AWS.Messaging/)套件。
+ [API 參考](https://aws.github.io/aws-dotnet-messaging/)。
+ GitHub 儲存庫中的 `README` 檔案位於 [https://github.com/aws/aws-dotnet-messaging/](https://github.com/aws/aws-dotnet-messaging/)
+ Microsoft 提供的 [.NET 相依性插入](https://learn.microsoft.com/en-us/dotnet/core/extensions/dependency-injection)。
+ Microsoft 的 [.NET Generic Host](https://learn.microsoft.com/en-us/dotnet/core/extensions/generic-host)。

**Topics**
+ [開始使用](msg-proc-fw-get-started.md)
+ [發佈訊息](msg-proc-fw-publish.md)
+ [使用訊息](msg-proc-fw-consume.md)
+ [FIFO](msg-proc-fw-fifo.md)
+ [記錄和開啟遙測](msg-proc-fw-telemetry.md)
+ [自訂](msg-proc-fw-customize.md)
+ [安全](msg-proc-fw-security.md)

# 開始使用適用於 .NET AWS 的訊息處理架構
<a name="msg-proc-fw-get-started"></a>

開始之前，請確定您已[設定環境和專案](net-dg-config.md)。也請檢閱 中的資訊[開發套件功能](net-dg-sdk-features.md)。

本主題提供的資訊可協助您開始使用訊息處理架構。除了先決條件和組態資訊之外，還提供教學課程，說明如何實作常見案例。

## 先決條件和組態
<a name="mpf-get-started-prereq"></a>
+ 您為應用程式提供的登入資料必須具有其使用的簡訊服務和操作的適當許可。如需詳細資訊，請參閱其各自開發人員指南中的 [SQS](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-authentication-and-access-control.html)、[SNS](https://docs.aws.amazon.com/sns/latest/dg/security-iam.html) 和 [EventBridge](https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-iam.html) 的安全主題。另請參閱 GitHub 上討論特定[許可](https://github.com/aws/aws-dotnet-messaging/blob/main/README.md#permissions)的 [README](https://github.com/aws/aws-dotnet-messaging/) 檔案部分。
+ 若要使用適用於 .NET AWS 的訊息處理架構，您必須將 [https://www.nuget.org/packages/AWS.Messaging](https://www.nuget.org/packages/AWS.Messaging) NuGet 套件新增至您的專案。例如：

  ```
  dotnet add package AWS.Messaging
  ```
+ 框架與 .NET 的[相依性注入 (DI) 服務容器](https://learn.microsoft.com/en-us/dotnet/core/extensions/dependency-injection)整合。您可以在應用程式啟動期間，呼叫 `AddAWSMessageBus`將其新增至 DI 容器來設定架構。

  ```
  var builder = WebApplication.CreateBuilder(args);
  
  // Register the AWS Message Processing Framework for .NET
  builder.Services.AddAWSMessageBus(builder =>
  {
      // Register that you'll publish messages of type ChatMessage to an existing queue
      builder.AddSQSPublisher<ChatMessage>("https://sqs.us-west-2.amazonaws.com/012345678910/MyAppProd");
  });
  ```

## 教學課程
<a name="mpf-get-started-tutorial"></a>

本教學課程示範如何使用適用於 .NET AWS 的訊息處理架構。它會建立兩個應用程式：在 API 端點收到請求時將訊息傳送至 Amazon SQS 佇列的 ASP.NET Core Minimal API，以及輪詢這些訊息並加以處理的長時間執行主控台應用程式。
+ 本教學中的指示偏好 .NET CLI，但您可以使用 .NET CLI 或 Microsoft Visual Studio 等跨平台工具來執行本教學課程。如需工具的資訊，請參閱 [安裝和設定您的工具鏈](net-dg-dev-env.md)。
+ 本教學假設您使用`[default]`設定檔做為登入資料。它還假設短期憑證可用，並具有傳送和接收 Amazon SQS 訊息的適當許可。如需詳細資訊，請參閱 [使用 設定 SDK 身分驗證 AWS](creds-idc.md)和 [SQS](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-authentication-and-access-control.html) 的安全主題。

**注意**  
透過執行本教學課程，您可能會產生 SQS 訊息的費用。

### 步驟
<a name="mpf-tutorial-steps"></a>
+ [建立 SQS 佇列](#mpf-tutorial-queue)
+ [建立並執行發佈應用程式](#mpf-tutorial-publish)
+ [建立並執行處理應用程式](#mpf-tutorial-handle)
+ [清除](#mpf-tutorial-cleanup)

### 建立 SQS 佇列
<a name="mpf-tutorial-queue"></a>

本教學課程需要 SQS 佇列來傳送訊息至 並從中接收訊息。您可以針對 AWS CLI 或 使用下列其中一個命令來建立佇列 AWS Tools for PowerShell。請記下傳回的佇列 URL，以便您可以在接下來的架構組態中指定該 URL。

------
#### [ AWS CLI ]

```
aws sqs create-queue --queue-name DemoQueue
```

------
#### [ AWS Tools for PowerShell ]

```
New-SQSQueue -QueueName DemoQueue
```

------

### 建立並執行發佈應用程式
<a name="mpf-tutorial-publish"></a>

使用下列程序來建立和執行發佈應用程式。

1. 開啟命令提示字元或終端機。尋找或建立可在其下建立 .NET 專案的作業系統資料夾。

1. 在該資料夾中，執行下列命令以建立 .NET 專案。

   ```
   dotnet new webapi --name Publisher
   ```

1. 導覽至新專案的資料夾。在適用於 .NET AWS 的訊息處理架構上新增相依性。

   ```
   cd Publisher
   dotnet add package AWS.Messaging
   ```
**注意**  
如果您使用 AWS IAM Identity Center 進行身分驗證，請務必同時新增 `AWSSDK.SSO`和 `AWSSDK.SSOOIDC`。

1. 使用`Program.cs`下列程式碼取代 中的程式碼。

   ```
   using AWS.Messaging;
   using Microsoft.AspNetCore.Mvc;
   using Publisher;
   
   var builder = WebApplication.CreateBuilder(args);
   
   // Add services to the container.
   // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle.
   builder.Services.AddEndpointsApiExplorer();
   builder.Services.AddSwaggerGen();
   
   
   // Configure the AWS Message Processing Framework for .NET.
   builder.Services.AddAWSMessageBus(builder =>
   {
       // Check for input SQS URL.
       // The SQS URL should be passed as a command line argument or set in the Debug launch profile.
       if ((args.Length == 1) && (args[0].Contains("https://sqs.")))
       {
           // Register that you'll publish messages of type GreetingMessage:
           // 1. To a specified queue.
           // 2. Using the message identifier "greetingMessage", which will be used
           //    by handlers to route the message to the appropriate handler.
           builder.AddSQSPublisher<GreetingMessage>(args[0], "greetingMessage");
       }
       // You can map additional message types to queues or topics here as well.
   });
   var app = builder.Build();
   
   
   // Configure the HTTP request pipeline.
   if (app.Environment.IsDevelopment())
   {
       app.UseSwagger();
       app.UseSwaggerUI();
   }
   
   app.UseHttpsRedirection();
   
   // Create an API Endpoint that receives GreetingMessage objects
   // from the caller and then sends them as an SQS message.
   app.MapPost("/greeting", async ([FromServices] IMessagePublisher publisher, Publisher.GreetingMessage message) =>
       {
           return await PostGreeting(message, publisher);
       })
   .WithName("SendGreeting")
   .WithOpenApi();
   
   app.Run();
   
   public partial class Program
   {
       /// <summary>
       /// Endpoint for posting a greeting message.
       /// </summary>
       /// <param name="greetingMessage">The greeting message.</param>
       /// <param name="messagePublisher">The message publisher.</param>
       /// <returns>Async task result.</returns>
       public static async Task<IResult> PostGreeting(GreetingMessage greetingMessage,
           IMessagePublisher messagePublisher)
       {
           if (greetingMessage.SenderName == null || greetingMessage.Greeting == null)
           {
               return Results.BadRequest();
           }
   
           // Publish the message to the queue configured above.
           await messagePublisher.PublishAsync(greetingMessage);
   
           return Results.Ok();
       }
   }
   
   namespace Publisher
   {
       /// <summary>
       /// This class represents the message contents.
       /// </summary>
       public class GreetingMessage
       {
           public string? SenderName { get; set; }
           public string? Greeting { get; set; }
       }
   }
   ```

1. 執行下列命令。這應該會使用 Swagger UI 開啟瀏覽器視窗，讓您探索和測試 API。

   ```
   dotnet watch run <queue URL created earlier>
   ```

1. 開啟`/greeting`端點，然後選擇**試用**。

1. 指定訊息的 `senderName`和 `greeting`值，然後選擇**執行**。這會叫用您的 API，以傳送 SQS 訊息。

### 建立並執行處理應用程式
<a name="mpf-tutorial-handle"></a>

使用下列程序來建立和執行處理應用程式。

1. 開啟命令提示字元或終端機。尋找或建立可在其下建立 .NET 專案的作業系統資料夾。

1. 在該資料夾中，執行下列命令以建立 .NET 專案。

   ```
   dotnet new console --name Handler
   ```

1. 導覽至新專案的資料夾。在適用於 .NET AWS 的訊息處理架構上新增相依性。同時新增 `Microsoft.Extensions.Hosting`套件，可讓您透過 [.NET Generic Host](https://learn.microsoft.com/en-us/dotnet/core/extensions/generic-host) 設定架構。

   ```
   cd Handler
   dotnet add package AWS.Messaging
   dotnet add package Microsoft.Extensions.Hosting
   ```
**注意**  
如果您使用 AWS IAM Identity Center 進行身分驗證，請務必同時新增 `AWSSDK.SSO`和 `AWSSDK.SSOOIDC`。

1. 使用`Program.cs`下列程式碼取代 中的程式碼。

   ```
   using AWS.Messaging;
   using Handler;
   using Microsoft.Extensions.DependencyInjection;
   using Microsoft.Extensions.Hosting;
   
   var builder = Host.CreateDefaultBuilder(args);
   
   builder.ConfigureServices(services =>
   {
       // Register the AWS Message Processing Framework for .NET.
       services.AddAWSMessageBus(builder =>
       {
           // Check for input SQS URL.
           // The SQS URL should be passed as a command line argument or set in the Debug launch profile.
           if ((args.Length == 1) && (args[0].Contains("https://sqs.")))
           {
               // Register you'll poll the following queue.
               builder.AddSQSPoller(args[0]);
   
               // And that messages of type "greetingMessage" should be:
               // 1. Deserialized as GreetingMessage objects.
               // 2. Which are then passed to GreetingMessageHandler.
               builder.AddMessageHandler<GreetingMessageHandler, GreetingMessage>("greetingMessage");
   
           }
           // You can add additional message handlers here, using different message types. 
       });
   });
   
   var host = builder.Build();
   await host.RunAsync();
   
   namespace Handler
   {
       /// <summary>
       /// This class represents the message contents.
       /// </summary>
       public class GreetingMessage
       {
           public string? SenderName { get; set; }
           public string? Greeting { get; set; }
       }
   
       /// <summary>
       /// This handler is invoked each time you receive the message.
       /// </summary>
       public class GreetingMessageHandler : IMessageHandler<GreetingMessage>
       {
           public Task<MessageProcessStatus> HandleAsync(
               MessageEnvelope<GreetingMessage> messageEnvelope,
               CancellationToken token = default)
           {
               Console.WriteLine(
                   $"Received message {messageEnvelope.Message.Greeting} from {messageEnvelope.Message.SenderName}");
               return Task.FromResult(MessageProcessStatus.Success());
           }
       }
   }
   ```

1. 執行下列命令。這會啟動長時間執行的輪詢器。

   ```
   dotnet run <queue URL created earlier>
   ```

   啟動後，應用程式很快就會收到本教學課程第一部分所傳送的訊息，並記錄下列訊息：

   ```
   Received message {greeting} from {senderName}
   ```

1. 按 `Ctrl+C` 停止輪詢器。

### 清除
<a name="mpf-tutorial-cleanup"></a>

使用下列其中一個命令，讓 AWS CLI 或 AWS Tools for PowerShell 刪除佇列。

------
#### [ AWS CLI ]

```
aws sqs delete-queue --queue-url "<queue URL created earlier>"
```

------
#### [ AWS Tools for PowerShell ]

```
Remove-SQSQueue -QueueUrl "<queue URL created earlier>"
```

------

# 使用適用於 .NET 的訊息處理架構發佈 AWS 訊息
<a name="msg-proc-fw-publish"></a>

.NET AWS 的訊息處理架構支援發佈一或多個訊息類型、處理一或多個訊息類型，或在相同的應用程式中同時執行兩者。

下列程式碼顯示將不同訊息類型發佈至不同 AWS 服務之應用程式的組態。

```
var builder = WebApplication.CreateBuilder(args);

// Register the AWS Message Processing Framework for .NET
builder.Services.AddAWSMessageBus(builder =>
{
    // Register that you'll send messages of type ChatMessage to an existing queue
    builder.AddSQSPublisher<ChatMessage>("https://sqs.us-west-2.amazonaws.com/012345678910/MyAppProd");

    // Register that you'll publish messages of type OrderInfo to an existing SNS topic
    builder.AddSNSPublisher<OrderInfo>("arn:aws:sns:us-west-2:012345678910:MyAppProd");

    // Register that you'll publish messages of type FoodItem to an existing EventBridge bus
    builder.AddEventBridgePublisher<FoodItem>("arn:aws:events:us-west-2:012345678910:event-bus/default");
});
```

在啟動期間註冊架構後，請將一般 插入`IMessagePublisher`您的程式碼。呼叫其`PublishAsync`方法以發佈上述設定的任何訊息類型。一般發佈者會根據訊息的類型，決定要將訊息路由到 的目的地。

 在下列範例中，ASP.NET MVC 控制器會收到來自使用者`ChatMessage`的訊息和`OrderInfo`事件，然後將其分別發佈到 Amazon SQS 和 Amazon SNS。這兩種訊息類型都可以使用上面設定的一般發佈者來發佈。

```
[ApiController]
[Route("[controller]")]
public class PublisherController : ControllerBase
{
    private readonly IMessagePublisher _messagePublisher;

    public PublisherController(IMessagePublisher messagePublisher)
    {
        _messagePublisher = messagePublisher;
    }

    [HttpPost("chatmessage", Name = "Chat Message")]
    public async Task<IActionResult> PublishChatMessage([FromBody] ChatMessage message)
    {
        // Perform business and validation logic on the ChatMessage here.
        if (message == null)
        {
            return BadRequest("A chat message was not submitted. Unable to forward to the message queue.");
        }
        if (string.IsNullOrEmpty(message.MessageDescription))
        {
            return BadRequest("The MessageDescription cannot be null or empty.");
        }

        // Send the ChatMessage to SQS, using the generic publisher.
        await _messagePublisher.PublishAsync(message);

        return Ok();
    }

    [HttpPost("order", Name = "Order")]
    public async Task<IActionResult> PublishOrder([FromBody] OrderInfo message)
    {
        if (message == null)
        {
            return BadRequest("An order was not submitted.");
        }

        // Publish the OrderInfo to SNS, using the generic publisher.
        await _messagePublisher.PublishAsync(message);

        return Ok();
    }
}
```

為了將訊息路由到適當的處理邏輯，架構會使用稱為*訊息類型識別符*的中繼資料。根據預設，這是訊息 .NET 類型的全名，包括其組件名稱。如果您同時傳送和處理訊息，如果您跨專案共用訊息物件的定義，則此機制會正常運作。不過，如果訊息是在不同的命名空間中重新定義，或者如果您要與其他架構或程式設計語言交換訊息，則您可能需要覆寫訊息類型識別符。

```
var builder = Host.CreateDefaultBuilder(args);

builder.ConfigureServices(services =>
{
    // Register the AWS Message Processing Framework for .NET
    services.AddAWSMessageBus(builder =>
    {
        // Register that you'll publish messages of type GreetingMessage to an existing queue
        builder.AddSQSPublisher<GreetingMessage>("https://sqs.us-west-2.amazonaws.com/012345678910/MyAppProd", "greetingMessage");
    });
});
```

## 服務特定的發佈者
<a name="service-specific-publishers"></a>

上述範例使用一般 `IMessagePublisher`，可根據設定的訊息類型發佈到任何支援的 AWS 服務。此架構也為 Amazon SQS、Amazon SNS 和 Amazon EventBridge 提供服務特定的發佈者。這些特定發佈者公開僅適用於該服務的選項，並且可以使用類型 `ISQSPublisher`、 `ISNSPublisher`和 注入`IEventBridgePublisher`。

例如，傳送訊息至 SQS FIFO 佇列時，您必須設定適當的[訊息群組 ID](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/FIFO-key-terms.html)。下列程式碼再次顯示`ChatMessage`範例，但現在使用 `ISQSPublisher`來設定 SQS 特定的選項。

```
public class PublisherController : ControllerBase
{
    private readonly ISQSPublisher _sqsPublisher;

    public PublisherController(ISQSPublisher sqsPublisher)
    {
        _sqsPublisher = sqsPublisher;
    }

    [HttpPost("chatmessage", Name = "Chat Message")]
    public async Task<IActionResult> PublishChatMessage([FromBody] ChatMessage message)
    {
        // Perform business and validation logic on the ChatMessage here
        if (message == null)
        {
            return BadRequest("A chat message was not submitted. Unable to forward to the message queue.");
        }
        if (string.IsNullOrEmpty(message.MessageDescription))
        {
            return BadRequest("The MessageDescription cannot be null or empty.");
        }

        // Send the ChatMessage to SQS using the injected ISQSPublisher, with SQS-specific options
        await _sqsPublisher.SendAsync(message, new SQSOptions
        {
            DelaySeconds = <delay-in-seconds>,
            MessageAttributes = <message-attributes>,
            MessageDeduplicationId = <message-deduplication-id>,
            MessageGroupId = <message-group-id>
        });

        return Ok();
    }
}
```

您可以`IEventBridgePublisher`分別使用 和 對 SNS `ISNSPublisher`和 EventBridge 進行相同的操作。

```
await _snsPublisher.PublishAsync(message, new SNSOptions
{
    Subject = <subject>,
    MessageAttributes = <message-attributes>,
    MessageDeduplicationId = <message-deduplication-id>,
    MessageGroupId = <message-group-id>
});
```

```
await _eventBridgePublisher.PublishAsync(message, new EventBridgeOptions
{
    DetailType = <detail-type>,
    Resources = <resources>,
    Source = <source>,
    Time = <time>,
    TraceHeader = <trace-header>
});
```

根據預設，指定類型的訊息會傳送至預先設定的目的地。不過，您可以使用訊息特定的發佈者覆寫單一訊息的目的地。您也可以覆寫用於發佈訊息的基礎 適用於 .NET 的 AWS SDK 用戶端，這在您需要變更角色或憑證的多租用戶應用程式中非常有用，視目的地而定。

```
await _sqsPublisher.SendAsync(message, new SQSOptions
{
    OverrideClient = <override IAmazonSQS client>,
    QueueUrl = <override queue URL>
});
```

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

.NET AWS 的訊息處理架構可讓您使用架構或其中一個訊息服務來取用已[發佈](msg-proc-fw-publish.md)的訊息。這些訊息可以透過各種方式使用，其中一些如下所述。

## 訊息處理常式
<a name="handle-a-message"></a>

若要取用訊息，請使用您要處理的每個訊息類型的`IMessageHandler`界面來實作訊息處理常式。訊息類型和訊息處理常式之間的映射是在專案啟動中設定。

```
await Host.CreateDefaultBuilder(args)
    .ConfigureServices(services =>
    {
        // Register the AWS Message Processing Framework for .NET
        services.AddAWSMessageBus(builder =>
        {
            // Register an SQS Queue that the framework will poll for messages.
            // NOTE: The URL given below is an example. Use the appropriate URL for your SQS Queue.
            builder.AddSQSPoller("https://sqs.us-west-2.amazonaws.com/012345678910/MyAppProd");

            // Register all IMessageHandler implementations with the message type they should process. 
            // Here messages that match our ChatMessage .NET type will be handled by our ChatMessageHandler
            builder.AddMessageHandler<ChatMessageHandler, ChatMessage>();
        });
    })
    .Build()
    .RunAsync();
```

下列程式碼顯示訊息的範例`ChatMessage`訊息處理常式。

```
public class ChatMessageHandler : IMessageHandler<ChatMessage>
{
    public Task<MessageProcessStatus> HandleAsync(MessageEnvelope<ChatMessage> messageEnvelope, CancellationToken token = default)
    {
        // Add business and validation logic here.
        if (messageEnvelope == null)
        {
            return Task.FromResult(MessageProcessStatus.Failed());
        }

        if (messageEnvelope.Message == null)
        {
            return Task.FromResult(MessageProcessStatus.Failed());
        }

        ChatMessage message = messageEnvelope.Message;

        Console.WriteLine($"Message Description: {message.MessageDescription}");

        // Return success so the framework will delete the message from the queue.
        return Task.FromResult(MessageProcessStatus.Success());
    }
}
```

外部`MessageEnvelope`包含架構使用的中繼資料。其`message`屬性是訊息類型 （在此案例中為 `ChatMessage`)。

您可以返回 `MessageProcessStatus.Success()` ，指出訊息已成功處理，架構將從 Amazon SQS 佇列刪除訊息。傳回 時`MessageProcessStatus.Failed()`，如果已設定，訊息將保留在佇列中，以供再次處理或移至[無效字母佇列](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-dead-letter-queues.html)。

## 在長時間執行的程序中處理訊息
<a name="long-running-process"></a>

您可以使用 `AddSQSPoller` SQS 佇列 URL 呼叫 ，以啟動長時間執行[https://learn.microsoft.com/en-us/dotnet/api/microsoft.extensions.hosting.backgroundservice](https://learn.microsoft.com/en-us/dotnet/api/microsoft.extensions.hosting.backgroundservice)，以持續輪詢佇列並處理訊息。

```
await Host.CreateDefaultBuilder(args)
    .ConfigureServices(services =>
    {
        // Register the AWS Message Processing Framework for .NET
        services.AddAWSMessageBus(builder =>
        {
            // Register an SQS Queue that the framework will poll for messages.
            // NOTE: The URL given below is an example. Use the appropriate URL for your SQS Queue.
            builder.AddSQSPoller("https://sqs.us-west-2.amazonaws.com/012345678910/MyAppProd", options => 
            {
                // The maximum number of messages from this queue that the framework will process concurrently on this client.
                options.MaxNumberOfConcurrentMessages = 10;

                // The duration each call to SQS will wait for new messages.
                options.WaitTimeSeconds = 20; 
            });

            // Register all IMessageHandler implementations with the message type they should process.
            builder.AddMessageHandler<ChatMessageHandler, ChatMessage>();
        });
    })
    .Build()
    .RunAsync();
```

### 設定 SQS 訊息輪詢器
<a name="config-msg-poller"></a>

呼叫 `SQSMessagePollerOptions`時， 可以設定 SQS 訊息輪詢器`AddSQSPoller`。
+ `MaxNumberOfConcurrentMessages` - 佇列中要同時處理的訊息數量上限。預設值為 10。
+ `WaitTimeSeconds` - `ReceiveMessage` SQS 呼叫在傳回前等待訊息抵達佇列的持續時間 （以秒為單位）。如果訊息可用，呼叫會比 更快傳回`WaitTimeSeconds`。預設值為 20。

**訊息可見性逾時處理**

SQS 訊息具有[可見性逾時](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-visibility-timeout.html)期間。當一個取用者開始處理指定的訊息時，它會保留在佇列中，但其他取用者會將其隱藏以避免處理超過一次。如果未在再次顯示訊息之前處理和刪除訊息，另一個消費者可能會嘗試處理相同的訊息。

框架會追蹤並嘗試延長目前正在處理之訊息的可見性逾時。您可以在呼叫 `SQSMessagePollerOptions`時，在 上設定此行為`AddSQSPoller`。
+ `VisibilityTimeout` - 從後續擷取請求中隱藏接收訊息的持續時間，以秒為單位。預設值為 30。
+ `VisibilityTimeoutExtensionThreshold` - 當訊息的可見性逾時在即將到期的這幾秒鐘內時，架構會將可見性逾時 （再延長一`VisibilityTimeout`秒鐘） 延長。預設值為 5。
+ `VisibilityTimeoutExtensionHeartbeatInterval` - 架構會在幾秒內檢查`VisibilityTimeoutExtensionThreshold`過期訊息，然後延長可見性逾時的頻率。預設值為 1。

 在下列範例中，架構將每 1 秒檢查一次仍在處理的訊息。對於再次顯示訊息的 5 秒內，框架會自動將每則訊息的可見性逾時延長 30 秒。

```
// NOTE: The URL given below is an example. Use the appropriate URL for your SQS Queue.
builder.AddSQSPoller("https://sqs.us-west-2.amazonaws.com/012345678910/MyAppProd", options => 
{
    options.VisibilityTimeout = 30;
    options.VisibilityTimeoutExtensionThreshold = 5;
    VisibilityTimeoutExtensionHeartbeatInterval = 1;
});
```

## 在 AWS Lambda 函數中處理訊息
<a name="lambda-functions"></a>

您可以使用適用於 .NET AWS 的訊息處理架構搭配 [SQS 與 Lambda 的整合](https://docs.aws.amazon.com/lambda/latest/dg/with-sqs.html)。這是由 `AWS.Messaging.Lambda`套件提供。請參閱其 [README](https://github.com/aws/aws-dotnet-messaging/blob/main/src/AWS.Messaging.Lambda/README.md) 以開始使用。

# 將 FIFO 與適用於 .NET AWS 的訊息處理架構搭配使用
<a name="msg-proc-fw-fifo"></a>

對於訊息排序和訊息重複資料刪除至關重要的使用案例，.NET AWS 的訊息處理架構支援first-in-first-out(FIFO) [Amazon SQS 佇列](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-fifo-queues.html)和 [Amazon SNS 主題](https://docs.aws.amazon.com/sns/latest/dg/sns-fifo-topics.html)。

## 發布
<a name="mpf-fifo-publish"></a>

將訊息發佈至 FIFO 佇列或主題時，您必須設定訊息群組 ID，以指定訊息所屬的群組。群組內的訊息會依序處理。您可以在 SQS 特定和 SNS 特定訊息發佈者上設定此項目。

```
await _sqsPublisher.PublishAsync(message, new SQSOptions
{
    MessageDeduplicationId = <message-deduplication-id>,
    MessageGroupId = <message-group-id>
});
```

## 訂閱
<a name="mpf-fifo-subscribe"></a>

處理來自 FIFO 佇列的訊息時，框架會依照每次`ReceiveMessages`呼叫收到訊息的順序，來處理指定訊息群組內的訊息。當設定佇列結尾為 時，框架會自動進入此操作模式`.fifo`。

```
await Host.CreateDefaultBuilder(args)
    .ConfigureServices(services =>
    {
        // Register the AWS Message Processing Framework for .NET.
        services.AddAWSMessageBus(builder =>
        {
            // Because this is a FIFO queue, the framework automatically handles these messages in order.
            builder.AddSQSPoller("https://sqs.us-west-2.amazonaws.com/012345678910/MPF.fifo");
            builder.AddMessageHandler<OrderMessageHandler, OrderMessage>();
        });
    })
    .Build()
    .RunAsync();
```

# 適用於 .NET AWS 的訊息處理架構的記錄和 Open Telemetry
<a name="msg-proc-fw-telemetry"></a>

.NET AWS 的訊息處理架構是針對 OpenTelemetry 進行檢測，以記錄架構發佈或處理的每個訊息[的追蹤](https://opentelemetry.io/docs/concepts/signals/traces/)。這是由 [https://www.nuget.org/packages/AWS.Messaging.Telemetry.OpenTelemetry](https://www.nuget.org/packages/AWS.Messaging.Telemetry.OpenTelemetry)套件提供。請參閱其 [README](https://github.com/aws/aws-dotnet-messaging/blob/main/src/AWS.Messaging.Telemetry.OpenTelemetry/README.md) 以開始使用。

**注意**  
如需記錄的相關安全資訊，請參閱 [適用於 .NET AWS 的訊息處理架構安全性](msg-proc-fw-security.md)。

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

.NET AWS 的訊息處理架構會在三個不同的「層」中建置、傳送和處理訊息：

1. 在最外層，架構會建置服務特有的 AWS原生請求或回應。例如，使用 Amazon SQS 可建置[https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_SendMessage.html](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_SendMessage.html)請求，並使用 服務定義的[https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_Message.html](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_Message.html)物件。

1. 在 SQS 請求和回應中，架構會將 `MessageBody`元素 （或 `Message` Amazon SNS 或 `Detail` Amazon EventBridge) 設定為 [JSON 格式的 CloudEvent](https://github.com/cloudevents/spec/blob/v1.0.2/cloudevents/formats/json-format.md)。這包含在處理訊息時，可在 `MessageEnvelope` 物件上存取之架構設定的中繼資料。

1. 在最內層，CloudEvent JSON 物件內的 `data` 屬性包含作為訊息傳送或接收的 .NET 物件的 JSON 序列化。

   ```
   {
       "id":"b02f156b-0f02-48cf-ae54-4fbbe05cffba",
       "source":"/aws/messaging",
       "specversion":"1.0",
       "type":"Publisher.Models.ChatMessage",
       "time":"2023-11-21T16:36:02.8957126+00:00",
       "data":"<the ChatMessage object serialized as JSON>"
   }
   ```

您可以自訂訊息信封的設定和讀取方式：
+ `"id"` 可唯一識別訊息。根據預設，它會設定為新的 GUID，但可以透過實作您自己的 `IMessageIdGenerator` 並將其插入 DI 容器來覆寫。
+ `"type"` 控制訊息路由到處理常式的方式。根據預設，這會使用與訊息對應的 .NET 類型完整名稱。透過 `AddSNSPublisher`、 或 將訊息類型映射至目的地時`AddSQSPublisher`，您可以透過 `messageTypeIdentifier` 參數覆寫此項目`AddEventBridgePublisher`。
+ `"source"` 指出哪個系統或伺服器傳送訊息。
  + 如果從 發佈，這會是函數名稱 AWS Lambda，如果在 Amazon ECS 上是叢集名稱和任務 ARN，如果在 Amazon EC2 上是執行個體 ID，則將是備用值 `/aws/messaging`。
  + 您可以透過 `AddMessageSource`或在 `AddMessageSourceSuffix`上覆寫此項目`MessageBusBuilder`。
+ `"time"` 設定為目前的 UTC DateTime。這可以透過實作您自己的 `IDateTimeHandler`並將其注入 DI 容器來覆寫。
+ `"data"` 包含作為訊息傳送或接收的 .NET 物件的 JSON 表示法：
  + `ConfigureSerializationOptions` 上的 `MessageBusBuilder`可讓您設定[https://learn.microsoft.com/en-us/dotnet/api/system.text.json.jsonserializeroptions](https://learn.microsoft.com/en-us/dotnet/api/system.text.json.jsonserializeroptions)序列化和還原序列化訊息時將使用的 。
  + 若要在架構建置後插入其他屬性或轉換訊息信封，您可以在 `AddSerializationCallback`上透過 實作`ISerializationCallback`並註冊該屬性`MessageBusBuilder`。

# 適用於 .NET AWS 的訊息處理架構安全性
<a name="msg-proc-fw-security"></a>

.NET AWS 的訊息處理架構倚賴 適用於 .NET 的 AWS SDK 與 通訊 AWS。如需 中安全性的詳細資訊 適用於 .NET 的 AWS SDK，請參閱 [此 AWS 產品或服務的安全性](security.md)。

基於安全考量，架構不會記錄使用者傳送的資料訊息。如果您想要啟用此功能進行偵錯，您需要在訊息匯流排`EnableDataMessageLogging()`中呼叫 ，如下所示：

```
builder.Services.AddAWSMessageBus(bus =>
{
    builder.EnableDataMessageLogging();
});
```

如果您發現潛在的安全問題，請參閱[安全性政策](https://github.com/aws/aws-dotnet-messaging/security/policy)以取得報告資訊。

# 在 中 AWS 與 .NET ACache 整合 適用於 .NET 的 AWS SDK
<a name="aspire-integrations"></a>

.NET Aspire 是建置雲端應用程式的新方法。特別是，它為要在其中執行、連線和偵錯分散式應用程式元件的本機環境提供協調。為了改善雲端就緒應用程式的內部開發迴圈，已建立與 .NET AShield 的整合，以將您的 .NET 應用程式連線至 AWS 資源。這些整合可透過 [Aspire.Hosting.AWS](https://www.nuget.org/packages/Aspire.Hosting.AWS) NuGet 套件取得。

下列 .NET Acsv 整合可供使用：
+ 透過 佈建 AWS 資源的能力[CloudFormation](https://aws.amazon.com/cloudformation/)。此整合用於 .NET AShield AppHost 專案中。

  如需詳細資訊，請參閱 部落格文章[AWS 與 .NET Aspire 整合](https://aws.amazon.com/blogs/developer/integrating-aws-with-net-aspire/)。
+ 安裝、設定並將 適用於 .NET 的 AWS SDK 連線至 [Amazon DynamoDB 本機](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocalHistory.html)。此整合用於 .NET AShield AppHost 專案中。

  如需詳細資訊，請參閱 部落格文章[AWS 與 .NET Aspire 整合](https://aws.amazon.com/blogs/developer/integrating-aws-with-net-aspire/)。
+ 為 [AWS Lambda](https://aws.amazon.com/lambda/)函數啟用本機開發環境。此整合用於 .NET AShield AppHost 專案中。

  如需詳細資訊，請參閱部落格文章建置[和偵錯 .NET Lambda 應用程式與 .NET Acsv （第 1 部分），](https://aws.amazon.com/blogs/developer/building-lambda-with-aspire-part-1/)以及[建置和偵錯 .NET Lambda 應用程式與 .NET Acsv （第 2 部分）](https://aws.amazon.com/blogs/developer/building-lambda-with-aspire-part-2/)。
**注意**  
這是預覽版本之服務的發行前版本文件。內容可能變動。

  由於此功能處於預覽狀態，您將需要選擇加入預覽功能。如需此預覽功能以及如何選擇加入的詳細資訊，請參閱 [ GitHub 上的開發追蹤器問題](https://github.com/aws/integrations-on-dotnet-aspire-for-aws/issues/17)。

## 其他資訊
<a name="aspire-integrations-additional"></a>

如需如何使用 [Aspire.Hosting.AWS](https://www.nuget.org/packages/Aspire.Hosting.AWS) 中可用整合的其他資訊和詳細資訊，請參閱下列資源。
+ 部落格文章[AWS 與 .NET Aspire 整合](https://aws.amazon.com/blogs/developer/integrating-aws-with-net-aspire/)。
+ 部落格發佈[使用 .NET Aspire （第 1 部分） 建置和偵錯 .NET Lambda 應用程式](https://aws.amazon.com/blogs/developer/building-lambda-with-aspire-part-1/)，以及[使用 .NET ACache （第 2 部分） 建置和偵錯 .NET Lambda 應用程式](https://aws.amazon.com/blogs/developer/building-lambda-with-aspire-part-2/)。
+ GitHub 上的 [integrations-on-dotnet-aspire-for-aws](https://github.com/aws/integrations-on-dotnet-aspire-for-aws) 儲存庫。
+ [Aspire.Hosting.AWS](https://www.nuget.org/packages/Aspire.Hosting.AWS) NuGet 套件的詳細 [README](https://github.com/aws/integrations-on-dotnet-aspire-for-aws/blob/main/src/Aspire.Hosting.AWS/README.md)。

# 支援其他 AWS 服務和組態
<a name="other-apis-intro"></a>

除了上述各節所述 AWS 的服務之外， 適用於 .NET 的 AWS SDK 還支援服務。如需所有支援服務 APIs的相關資訊，請參閱 [適用於 .NET 的 AWS SDK API 參考](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/)。

除了個別 AWS 服務的命名空間之外， 適用於 .NET 的 AWS SDK 還提供下列 APIs：


****  

| 區域圖 | 描述 | 資源 | 
| --- | --- | --- | 
|  AWS 支援  |  以程式設計方式存取 AWS 支援案例和 Trusted Advisor 功能。  |  請參閱 [Amazon.AWSSupport](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/AWSSupport/NAWSSupport.html) 和 [Amazon.AWSSupport.Model](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/AWSSupport/NAWSSupportModel.html)。  | 
|  一般  |  協助程式和列舉。  |  請參閱 [Amazon](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/Amazon/N.html) 和 [Amazon.Util](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/Util/NUtil.html)。  | 