

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

# 使用 C\$1 建置 Lambda 函數
<a name="lambda-csharp"></a>

您可以使用受管 .NET 8 執行時間、自訂執行時間或容器映像，在 Lambda 中執行 .NET 應用程式。編譯應用程式程式碼之後，您能以 .zip 檔或容器映像檔形式部署至 Lambda。Lambda 提供適用於 .NET 語言的以下執行期：


| Name | 識別符 | 作業系統 | 取代日期 | 封鎖函數建立 | 封鎖函數更新 | 
| --- | --- | --- | --- | --- | --- | 
|  .NET 10  |  `dotnet10`  |  Amazon Linux 2023  |   2028 年 11 月 14 日   |   2028 年 12 月 14 日   |   2029 年 1 月 15 日   | 
|  .NET 9 （僅限容器）  |  `dotnet9`  |  Amazon Linux 2023  |   2026 年 11 月 10 日   |   未排程   |   未排程   | 
|  .NET 8  |  `dotnet8`  |  Amazon Linux 2023  |   2026 年 11 月 10 日   |   2026 年 12 月 10 日   |   2027 年 1 月 11 日   | 

## 設定您的 .NET 開發環境
<a name="csharp-dev-env"></a>

若要開發和建置 Lambda 函數，您可以使用任何常用的 .NET 整合式開發環境 (IDE)，包括 Microsoft Visual Studio、Visual Studio Code 和 JetBrains Rider。為了簡化您的開發體驗， AWS 提供一組 .NET 專案範本以及`Amazon.Lambda.Tools`命令列界面 (CLI)。

執行下列 .NET CLI 命令，即可安裝這些專案範本和命令列工具。

### 安裝 .NET 專案範本
<a name="csharp-dev-env-templates"></a>

若要安裝專案範本，請執行下列命令：

```
dotnet new install Amazon.Lambda.Templates
```

### 安裝和更新 CLI 工具
<a name="csharp-dev-env-cli-tools"></a>

執行下列命令來安裝、更新和解除安裝 `Amazon.Lambda.Tools` CLI。

若要安裝命令列工具，請執行以下操作：

```
dotnet tool install -g Amazon.Lambda.Tools
```

若要更新命令列工具，請執行以下操作：

```
dotnet tool update -g Amazon.Lambda.Tools
```

若要解除安裝命令列工具，請執行以下操作：

```
dotnet tool uninstall -g Amazon.Lambda.Tools
```

# 定義 C\$1 格式的 Lambda 函數處理常式
<a name="csharp-handler"></a>

Lambda 函數*處理常式*是您的函數程式碼中處理事件的方法。當有人呼叫您的函數時，Lambda 會執行處理常式方法。函數會執行，直到處理常式傳回回應、結束或逾時為止。

本頁介紹了如何在 C\$1 中將 Lambda 函式處理常式與 .NET 受管執行時期搭配使用，包括專案設定選項、命名慣例及最佳實務。本頁還提供了一個 C\$1 Lambda 函式範例，該函式會取得訂單的相關資訊、產生文字檔案收據，並將該檔案放入 Amazon Simple Storage Service (S3) 儲存貯體。如需編寫函數後如何部署函數的詳細資訊，請參閱[使用 .zip 封存檔建置和部署 C＃ Lambda 函數](csharp-package.md)或[使用容器映像部署 .NET Lambda 函數](csharp-image.md)。

**Topics**
+ [

## 設定 C\$1 處理常式專案
](#csharp-handler-setup)
+ [

## C\$1 Lambda 函式程式碼範例
](#csharp-example-code)
+ [

## 類別庫處理常式
](#csharp-class-library-handlers)
+ [

## 可執行組件處理常式
](#csharp-executable-assembly-handlers)
+ [

## C\$1 函式的有效處理常式簽章
](#csharp-handler-signatures)
+ [

## 處理常式命名慣例
](#csharp-handler-naming)
+ [

## C\$1 Lambda 函式中的序列化
](#csharp-handler-serializer)
+ [

## 以檔案為基礎的函數
](#csharp-file-based-functions)
+ [

## 存取和使用 Lambda 內容物件
](#csharp-example-context)
+ [

## 在處理常式中使用 適用於 .NET 的 SDK v3
](#csharp-example-sdk-usage)
+ [

## 存取環境變數
](#csharp-example-envvars)
+ [

## 使用全域狀態
](#csharp-handler-state)
+ [

## 使用 Lambda Annotations 架構簡化函數程式碼
](#csharp-handler-annotations)
+ [

## C\$1 Lambda 函數的程式碼最佳實務
](#csharp-best-practices)

## 設定 C\$1 處理常式專案
<a name="csharp-handler-setup"></a>

使用 C\$1 開發 Lambda 函式時，流程涉及編寫程式碼以及將程式碼部署至 Lambda。有兩種不同的執行模型可用於在 .NET 中部署 Lambda 函式：類別庫方法和可執行組件方法。

在類別庫方法中，您需將函式程式碼封裝為 .NET 組件 (`.dll`)，並透過 .NET 受管執行時期 (`dotnet8`) 將其部署至 Lambda。對於處理常式名稱，Lambda 期望字串的格式為 `AssemblyName::Namespace.Classname::Methodname`。在函數的初始化階段，系統會初始化函數的類別，並執行建構函數中的任何程式碼。

在可執行組件方法中，您可以使用 C\$1 9 中首次推出的[頂層陳述式功能](https://learn.microsoft.com/en-us/dotnet/csharp/tutorials/top-level-statements)。此方法會產生一個可執行組件，每當 Lambda 收到函數的調用命令時，就會執行該組件。此方法也會使用 .NET 受管執行時期 (`dotnet8`)。對於處理常式名稱，您需要將要執行的可執行組件名稱提供給 Lambda。

本頁上的主要範例示範了類別庫方法。您可以透過各種方式初始化 C\$1 Lambda 專案，但最簡單的方法是搭配 `Amazon.Lambda.Tools` CLI 使用 .NET CLI。依照中[設定您的 .NET 開發環境](lambda-csharp.md#csharp-dev-env)的步驟設定 `Amazon.Lambda.Tools` CLI。接著，使用下列命令初始化專案：

```
dotnet new lambda.EmptyFunction --name ExampleCS
```

此命令會產生下列檔案結構：

```
/project-root 
    └ src
        └ ExampleCS
            └ Function.cs (contains main handler)
            └ Readme.md
            └ aws-lambda-tools-defaults.json
            └ ExampleCS.csproj          
    └ test
         └ ExampleCS.Tests
            └ FunctionTest.cs (contains main handler)
            └ ExampleCS.Tests.csproj
```

在此檔案結構中，函式的主要處理常式邏輯位於 `Function.cs` 檔案中。

## C\$1 Lambda 函式程式碼範例
<a name="csharp-example-code"></a>

以下 C\$1 Lambda 函式程式碼範例會取得訂單的相關資訊、產生文字檔案收據，並將該檔案放入 Amazon S3 儲存貯體。

**Example `Function.cs` Lambda 函數**  

```
using System;
using System.Text;
using System.Threading.Tasks;
using Amazon.Lambda.Core;
using Amazon.S3;
using Amazon.S3.Model;

// Assembly attribute to enable Lambda function logging
[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))]

namespace ExampleLambda;

public class Order
{
    public string OrderId { get; set; } = string.Empty;
    public double Amount { get; set; }
    public string Item { get; set; } = string.Empty;
}

public class OrderHandler
{
    private static readonly AmazonS3Client s3Client = new();

    public async Task<string> HandleRequest(Order order, ILambdaContext context)
    {
        try
        {
            string? bucketName = Environment.GetEnvironmentVariable("RECEIPT_BUCKET");
            if (string.IsNullOrWhiteSpace(bucketName))
            {
                throw new ArgumentException("RECEIPT_BUCKET environment variable is not set");
            }

            string receiptContent = $"OrderID: {order.OrderId}\nAmount: ${order.Amount:F2}\nItem: {order.Item}";
            string key = $"receipts/{order.OrderId}.txt";

            await UploadReceiptToS3(bucketName, key, receiptContent);

            context.Logger.LogInformation($"Successfully processed order {order.OrderId} and stored receipt in S3 bucket {bucketName}");
            return "Success";
        }
        catch (Exception ex)
        {
            context.Logger.LogError($"Failed to process order: {ex.Message}");
            throw;
        }
    }

    private async Task UploadReceiptToS3(string bucketName, string key, string receiptContent)
    {
        try
        {
            var putRequest = new PutObjectRequest
            {
                BucketName = bucketName,
                Key = key,
                ContentBody = receiptContent,
                ContentType = "text/plain"
            };

            await s3Client.PutObjectAsync(putRequest);
        }
        catch (AmazonS3Exception ex)
        {
            throw new Exception($"Failed to upload receipt to S3: {ex.Message}", ex);
        }
    }
}
```

此 `Function.cs` 檔案包含以下程式碼區段：
+ `using` 陳述式：使用這些陳述式來匯入 Lambda 函式所需的 C\$1 類別。
+ `[assembly: LambdaSerializer(...)]`：`LambdaSerializer` 是組件屬性，指示 Lambda 先自動將 JSON 事件承載轉換為 C\$1 物件之後再傳遞至函式。
+ `namespace ExampleLambda`：此程式碼會定義命名空間。在 C\$1 中，命名空間名稱不必與檔案名稱相符。
+ `public class Order {...}`：此程式碼會定義預期輸入事件的結構。
+ `public class OrderHandler {...}`：此程式碼會定義 C\$1 類別。您可以在其中定義主要處理常式方法及其他輔助方法。
+ `private static readonly AmazonS3Client s3Client = new();`：此程式碼會在主要處理常式方法外部，透過預設憑證提供者鏈初始化 Amazon S3 用戶端。這會使 Lambda 在[初始化階段](lambda-runtime-environment.md#runtimes-lifecycle-ib)執行此程式碼。
+ `public async ... HandleRequest (Order order, ILambdaContext context)`：這是**主要處理常式方法**，其中包含應用程式的主要邏輯。
+ `private async Task UploadReceiptToS3(...) {}`：這是主要 `handleRequest` 處理常式方法所參照的輔助方法。

由於此函式需要 Amazon S3 SDK 用戶端，因此您必須將其新增至專案的相依項。您可以導覽至 `src/ExampleCS` 並執行下列命令來完成此操作：

```
dotnet add package AWSSDK.S3
```

### 將中繼資料資訊新增至 aws-lambda-tools-defaults.json
<a name="csharp-metadata-example"></a>

依預設，產生的 `aws-lambda-tools-defaults.json` 檔案不包含函式的 `profile` 或 `region` 資訊。此外，請將 `function-handler` 字串更新為正確的值 (`ExampleCS::ExampleLambda.OrderHandler::HandleRequest`)。您可以手動自行此更新作業，並新增必要的中繼資料，以便函式使用特定的憑證設定檔與區域。例如，`aws-lambda-tools-defaults.json` 檔案應該與下列範例類似：

```
{
  "Information": [
    "This file provides default values for the deployment wizard inside Visual Studio and the AWS Lambda commands added to the .NET Core CLI.",
    "To learn more about the Lambda commands with the .NET Core CLI execute the following command at the command line in the project root directory.",
    "dotnet lambda help",
    "All the command line options for the Lambda command can be specified in this file."
  ],
  "profile": "default",
  "region": "us-east-1",
  "configuration": "Release",
  "function-architecture": "x86_64",
  "function-runtime": "dotnet8",
  "function-memory-size": 512,
  "function-timeout": 30,
  "function-handler": "ExampleCS::ExampleLambda.OrderHandler::HandleRequest"
}
```

若要讓此函式正常運作，其[執行角色](lambda-intro-execution-role.md)必須允許 `s3:PutObject` 動作。此外，請確保定義 `RECEIPT_BUCKET` 環境變數。成功調用後，Amazon S3 儲存貯體應包含收據檔案。

## 類別庫處理常式
<a name="csharp-class-library-handlers"></a>

本頁上的主要[範例程式碼](#csharp-example-code)示範了類別庫處理常式。類別庫處理常式具有下列結構：

```
[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))]

namespace NAMESPACE;

...

public class CLASSNAME {
    public async Task<string> METHODNAME (...) {
    ...
    }
}
```

建立 Lambda 函式時，需要以字串的形式在[處理常式欄位](https://docs.aws.amazon.com/lambda/latest/api/API_CreateFunction.html#lambda-CreateFunction-request-Handler)中向 Lambda 提供函式處理常式的相關資訊。目的是指示 Lambda 在調用函數時要在程式碼中執行哪種方法。在 C\$1 中，對於類別庫處理常式，處理常式字串的格式為 `ASSEMBLY::TYPE::METHOD`，其中：
+ `ASSEMBLY` 是應用程式的 .NET 組件名稱。如果您使用 `Amazon.Lambda.Tools` CLI 建置應用程式，而沒有使用 `.csproj` 檔案中的 `AssemblyName` 屬性來設定組件名稱，則 `ASSEMBLY` 即為 `.csproj` 檔案的名稱。
+ `TYPE` 是處理常式類型的完整名稱，即 `NAMESPACE.CLASSNAME`。
+ `METHOD` 是程式碼中主要處理常式方法的名稱，即 `METHODNAME`。

在本頁上的主要範例程式碼中，如果組件名為 `ExampleCS`，則完整處理常式字串為 `ExampleCS::ExampleLambda.OrderHandler::HandleRequest`。

## 可執行組件處理常式
<a name="csharp-executable-assembly-handlers"></a>

您也可以在 C\$1 中將 Lambda 函式定義為可執行組件。可執行組件處理常式利用 C\$1 的頂層陳述式功能。在該功能中，編譯器會產生 `Main()` 方法，並將函式程式碼放入其中。使用可執行組件時，必須引導 Lambda 執行期。若要執行此操作，請在程式碼中使用 `LambdaBootstrapBuilder.Create` 方法。此方法的輸入參數包含主要處理常式函式以及要使用的 Lambda 序列化程式。以下所示為 C\$1 中可執行組件處理常式的範例：

```
namespace GetProductHandler;

IDatabaseRepository repo = new DatabaseRepository();

await LambdaBootstrapBuilder.Create<APIGatewayProxyRequest>(Handler, new DefaultLambdaJsonSerializer())
    .Build()
    .RunAsync();

async Task<APIGatewayProxyResponse> Handler(APIGatewayProxyRequest apigProxyEvent, ILambdaContext context)
{
    var id = apigProxyEvent.PathParameters["id"];
    var databaseRecord = await this.repo.GetById(id);
    
    return new APIGatewayProxyResponse 
    {
        StatusCode = (int)HttpStatusCode.OK,
        Body = JsonSerializer.Serialize(databaseRecord)
    };
};
```

在可執行組件處理常式的[處理常式欄位](https://docs.aws.amazon.com/lambda/latest/api/API_CreateFunction.html#lambda-CreateFunction-request-Handler)中，指示 Lambda 如何執行程式碼的處理常式字串就是組件的名稱。在此範例中，該名稱為 `GetProductHandler`。

## C\$1 函式的有效處理常式簽章
<a name="csharp-handler-signatures"></a>

在 C\$1 中，有效的 Lambda 處理常式簽章包含 0 到 2 個引數。一般而言，處理常式簽章有兩個引數，如主要範例所示：

```
public async Task<string> HandleRequest(Order order, ILambdaContext context)
```

提供兩個引數時，第一個引數必須是事件輸入，第二個引數必須是 Lambda 內容物件。這兩個引數皆為選用。例如，以下 C\$1 中的 Lambda 處理常式簽章同樣有效：
+ `public async Task<string> HandleRequest()`
+ `public async Task<string> HandleRequest(Order order)`
+ `public async Task<string> HandleRequest(ILambdaContext context)`

除處理常式簽章的基礎語法外，另有一些額外限制：
+ 處理常式簽章中不得使用 `unsafe` 關鍵字。但處理常式方法及其相依項中可使用 `unsafe` 內容。如需詳細資訊，請參閱 Microsoft 文件網站上的 [unsafe (C\$1 reference)](https://msdn.microsoft.com/en-us/library/chfa2zb8.aspx)。
+ 處理常式不得使用 `params` 關鍵字，也不得將 `ArgIterator` 作為輸入或傳回參數。這些關鍵字支援可變數量的參數。處理常式最多能接受兩個引數。
+ 處理常式不可為泛型方法。換言之，其無法使用泛型類型參數，例如 `<T>`。
+ Lambda 不支援簽章中包含 `async void` 的非同步處理常式。

## 處理常式命名慣例
<a name="csharp-handler-naming"></a>

C\$1 中的 Lambda 處理常式沒有嚴格的命名限制。不過，在部署函式時，必須確保向 Lambda 提供正確的處理常式字串。正確的處理常式字串視您要部署的是[類別庫處理常式](#csharp-class-library-handlers)還是[可執行組件處理常式](#csharp-executable-assembly-handlers)而定。

雖然您可以為處理常式使用任何名稱，但 C\$1 中的函式名稱通常採用 PascalCase 命名方式。此外，雖然檔案名稱無需與類別名稱或處理常式名稱相符，但最佳實務通常是讓二者保持一致：例如類別名稱為 `OrderHandler`，檔案名稱則為 `OrderHandler.cs`。舉例而言，您可以將此範例中的檔案名稱從 `Function.cs` 修改為 `OrderHandler.cs`。

## C\$1 Lambda 函式中的序列化
<a name="csharp-handler-serializer"></a>

JSON 是 Lambda 函數最常見的標準輸入格式。在此範例中，函數預期輸入類似以下內容：

```
{
    "orderId": "12345",
    "amount": 199.99,
    "item": "Wireless Headphones"
}
```

在 C\$1 中，您可以定義類別中預期輸入事件的結構。在此範例中，我們定義 `Order` 類別來模擬這種輸入：

```
public class Order
{
    public string OrderId { get; set; } = string.Empty;
    public double Amount { get; set; }
    public string Item { get; set; } = string.Empty;
}
```

若您的 Lambda 函數使用輸入或輸出類型而非 `Stream` 物件，您必須將序列化程式庫新增至您的應用程式。如此，您可以將 JSON 輸入轉換為您所定義類別的執行個體。Lambda 中 C\$1 函式的序列化方法分為兩種：反射式序列化與原始碼產生式序列化。

### 反射式序列化
<a name="csharp-reflection-based-serialization"></a>

AWS 提供預先建置的程式庫，您可以快速新增至您的應用程式。這些程式庫使用[反射](https://learn.microsoft.com/en-us/dotnet/csharp/advanced-topics/reflection-and-attributes/)實作序列化。使用下列任一套件實作反射式序列化：
+ `Amazon.Lambda.Serialization.SystemTextJson` – 此套件在後端透過 `System.Text.Json` 執行序列化任務。
+ `Amazon.Lambda.Serialization.Json` – 此套件在後端透過 `Newtonsoft.Json` 執行序列化任務。

您也可以實作 `ILambdaSerializer` 界面 (隨 `Amazon.Lambda.Core` 程式庫提供) 來建立自己的序列化程式庫。此界面定義了兩種方法：
+ `T Deserialize<T>(Stream requestStream);`

  若實作此方法，會將請求承載從 `Invoke` API 還原序列化至傳遞到 Lambda 函數處理常式的物件。
+ `T Serialize<T>(T response, Stream responseStream);`

  若實作此方法，會將從 Lambda 函數處理常式傳回的結果，序列化至 `Invoke` API 作業傳回的回應承載中。

本頁上的主要範例使用反射式序列化。以反射為基礎的序列化可立即搭配 運作 AWS Lambda ，無需額外設定，因此是簡化的理想選擇。不過，此方式確需佔用更多函式記憶體。由於執行時期反射，函式延遲也可能會更高。

### 原始碼產生式序列化
<a name="csharp-source-generated-serialization"></a>

透過原始碼產生式序列化，序列化程式碼會在編譯時產生。此方式不需要使用反射，並且可提高函式的效能。若要在函式中使用原始碼產生式序列化，請執行以下操作：
+ 建立一個繼承自 `JsonSerializerContext` 的新部分分類，為需要序列化或還原序列化的所有類型新增 `JsonSerializable` 屬性。
+ 設定 `LambdaSerializer` 以使用 `SourceGeneratorLambdaJsonSerializer<T>`。
+ 更新應用程式程式碼中的任何手動序列化與反序列化，以使用新建立的類別。

下列範例示範了如何修改本頁上採用反射式序列化的主要範例，使其改為使用原始碼產生式序列化。

```
using System.Text.Json;
using System.Text.Json.Serialization;

...

public class Order
{
    public string OrderId { get; set; } = string.Empty;
    public double Amount { get; set; }
    public string Item { get; set; } = string.Empty;
}

[JsonSerializable(typeof(Order))]
public partial class OrderJsonContext : JsonSerializerContext {}

public class OrderHandler
{

    ...

    public async Task<string> HandleRequest(string input, ILambdaContext context)
    {
    
    var order = JsonSerializer.Deserialize(input, OrderJsonContext.Default.Order);
    
    ...
    
    }

}
```

與反射式序列化相比，原始碼產生式序列化需要更多的設定。不過，由於程式碼在編譯時產生，因此使用原始碼產生式序列化的函式通常佔用較少的記憶體，並具有更好的效能。為協助消除函式[冷啟動](lambda-runtime-environment.md#cold-start-latency)，建議改為使用原始碼產生式序列化。

**注意**  
如果您想透過 Lambda 使用原生[預先編譯 (AOT)](dotnet-native-aot.md)，必須使用原始碼產生式序列化。

## 以檔案為基礎的函數
<a name="csharp-file-based-functions"></a>

在 .NET 10 中推出以檔案為基礎的應用程式，可讓您從單一`.cs`檔案建置 .NET 應用程式，而不需要`.csproj`檔案或目錄結構。Lambda 支援以檔案為基礎的函數，從 .NET 10 開始。它們提供簡化、輕量的方式來在 C\$1 中建置 Lambda 函數。

開始建立 C\$1 檔案型 Lambda 函數的最快方法是使用 `Amazon.Lambda.Templates`套件。若要安裝此套件，請執行下列命令：

```
dotnet new install Amazon.Lambda.Templates
```

接著，建立 C\$1 檔案型 Lambda 範例函數：

```
dotnet new lambda.FileBased -n MyLambdaFunction
```

以檔案為基礎的函數使用[可執行的組件處理常式](#csharp-executable-assembly-handlers)。因此，您必須包含 `Amazon.Lambda.RuntimeSupport` NuGet 套件，並使用 `LambdaBootstrapBuilder.Create`方法來註冊事件類型的 .NET 處理常式函數，並啟動 .NET Lambda 執行期用戶端。

根據預設，以檔案為基礎的函數會使用 .NET Native AOT，這需要來源產生的序列化。您可以在`#:property PublishAot=false`來源檔案中指定 來停用原生 AOT。如需在 Lambda 中使用原生 AOT 的詳細資訊，請參閱 [將 .NET Lambda 函數程式碼編譯為原生執行時期格式](dotnet-native-aot.md)。

## 存取和使用 Lambda 內容物件
<a name="csharp-example-context"></a>

Lambda [內容物件](csharp-context.md) 包含有關調用、函數以及執行環境的資訊。在此範例中，內容物件的類型為 `Amazon.Lambda.Core.ILambdaContext`，並且內容物件也是主要處理常式函式的第二個引數。

```
public async Task<string> HandleRequest(Order order, ILambdaContext context) {
    ...
}
```

內容物件為選用輸入。如需有關可接受的有效處理常式簽章的詳細資訊，請參閱 [C\$1 函式的有效處理常式簽章](#csharp-handler-signatures)。

內容物件有助於將函式日誌輸出至 Amazon CloudWatch。您可以使用 `context.getLogger()` 方法取得用於記錄日誌的 `LambdaLogger` 物件。在此範例中，如果處理因任何原因失敗，我們可以使用記錄器來記錄錯誤訊息：

```
context.Logger.LogError($"Failed to process order: {ex.Message}");
```

除了記錄日誌之外，您還可以將內容物件用於函式監控。如需內容物件的詳細資訊，請參閱[使用 Lambda 內容物件擷取 C\$1 函數資訊](csharp-context.md)。

## 在處理常式中使用 適用於 .NET 的 SDK v3
<a name="csharp-example-sdk-usage"></a>

通常，您將使用 Lambda 函數與其他 AWS 資源互動或進行更新。與這些資源互動的最簡單方法是使用 適用於 .NET 的 SDK v3。

**注意**  
 適用於 .NET 的 SDK (v2) 已棄用。我們建議您僅使用 適用於 .NET 的 SDK v3。

您可以透過下列 `Amazon.Lambda.Tools` 命令將 SDK 相依項新增至專案：

```
dotnet add package <package_name>
```

例如，在本頁上的主要範例中，我們需透過 Amazon S3 API 將收據上傳至 S3。我們可以使用下列命令匯入 Amazon S3 SDK 用戶端：

```
dotnet add package AWSSDK.S3
```

此命令會將相依項新增至專案。您應該也會在專案的 `.csproj` 檔案中看到類似下列的程式碼行：

```
<PackageReference Include="AWSSDK.S3" Version="3.7.2.18" />
```

然後，直接在 C\$1 程式碼中匯入相依項：

```
using Amazon.S3;
using Amazon.S3.Model;
```

範例程式碼接著會初始化 Amazon S3 用戶端 (使用[預設憑證提供者鏈](https://docs.aws.amazon.com/sdkref/latest/guide/standardized-credentials.html))，如下所示：

```
private static readonly AmazonS3Client s3Client = new();
```

在此範例中，我們在主要處理常式函式外部初始化 Amazon S3 用戶端，以免每次調用函式時都必須初始化該用戶端。初始化 SDK 用戶端之後，您可以使用它來與其他 AWS 服務互動。此範例程式碼會呼叫 Amazon S3 `PutObject` API，如下所示：

```
var putRequest = new PutObjectRequest
{
    BucketName = bucketName,
    Key = key,
    ContentBody = receiptContent,
    ContentType = "text/plain"
};

await s3Client.PutObjectAsync(putRequest);
```

## 存取環境變數
<a name="csharp-example-envvars"></a>

在處理常式程式碼中，您可以使用 `System.Environment.GetEnvironmentVariable` 方法來引用任何[環境變數](configuration-envvars.md)。在此範例中，我們使用下列程式碼行來引用定義的 `RECEIPT_BUCKET` 環境變數：

```
string? bucketName = Environment.GetEnvironmentVariable("RECEIPT_BUCKET");
if (string.IsNullOrWhiteSpace(bucketName))
{
    throw new ArgumentException("RECEIPT_BUCKET environment variable is not set");
}
```

## 使用全域狀態
<a name="csharp-handler-state"></a>

在首次調用函數之前，Lambda 會在[初始化階段](lambda-runtime-environment.md#runtimes-lifecycle-ib)執行靜態程式碼和類別建構函數。在初始化期間建立的資源會在調用間隔期間保留在記憶體中，無需您在每次調用函式時都建立這些資源。

在範例程式碼中，S3 用戶端初始化程式碼位於主要處理常式方法外部。執行時期會在函式處理其第一個事件之前初始化用戶端，這可能導致處理時間延長。但後續事件的處理速度會大幅提升，因為 Lambda 無需再次初始化用戶端。

## 使用 Lambda Annotations 架構簡化函數程式碼
<a name="csharp-handler-annotations"></a>

[Lambda Annotations](https://www.nuget.org/packages/Amazon.Lambda.Annotations) 是一套適用於 .NET 8 的架構，簡化了使用 C＃ 編寫 Lambda 函式的程序。Annotations 架構使用[原始碼產生器](https://learn.microsoft.com/en-us/dotnet/csharp/roslyn-sdk/source-generators-overview)來產生程式碼，將 Lambda 程式設計模型轉換為簡化的程式碼。透過 Annotations 架構，您可以取代使用一般程式設計模型編寫的大部分 Lambda 函數程式碼。使用此架構編寫的程式碼使用更簡單的表達式，讓您可專注於商業邏輯。如需相關範例，請參閱 nuget 文件中的 [Amazon.Lambda.Annotations](https://www.nuget.org/packages/Amazon.Lambda.Annotations)。

如需使用 Lambda Annotations 的完整應用程式範例，請參閱 `awsdocs/aws-doc-sdk-examples` GitHub 儲存庫中的 [ PhotoAssetManager](https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/dotnetv3/cross-service/PhotoAssetManager) 範例。`PamApiAnnotations` 目錄中的主要 `Function.cs` 檔案使用 Lambda Annotations。為了進行比較，`PamApi` 目錄包含使用常規 Lambda 程式設計模型編寫的對等檔案。

### 使用 Lambda Annotations 架構進行相依性插入
<a name="csharp-handler-annotations-injection"></a>

您也可以透過 Lambda Annotations 架構，使用熟悉的語法將相依性插入新增至 Lambda 函數。將 `[LambdaStartup]` 屬性新增至 `Startup.cs` 檔案時，Lambda Annotations 架構會在編譯時產生所需的程式碼。

```
[LambdaStartup]
public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddSingleton<IDatabaseRepository, DatabaseRepository>();
    }
}
```

Lambda 函數可以使用建構函數插入來插入服務，或使用 `[FromServices]` 屬性插入個別方法中。

```
[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))]

namespace GetProductHandler;

public class Function
{
    private readonly IDatabaseRepository _repo;
    
    public Function(IDatabaseRepository repo)
    {
        this._repo = repo;
    }
    
    [LambdaFunction]
    [HttpApi(LambdaHttpMethod.Get, "/product/{id}")]
    public async Task<Product> FunctionHandler([FromServices] IDatabaseRepository repository, string id)
    {
        return await this._repo.GetById(id);
    }
}
```

## C\$1 Lambda 函數的程式碼最佳實務
<a name="csharp-best-practices"></a>

請遵循下列清單中的準則，在建置 Lambda 函數時使用最佳編碼實務：
+ **區隔 Lambda 處理常式與您的核心邏輯。**能允許您製作更多可測單位的函式。
+ **控制函數部署套件內的相依性。** AWS Lambda 執行環境包含多個程式庫。若要啟用最新的一組功能與安全更新，Lambda 會定期更新這些程式庫。這些更新可能會為您的 Lambda 函數行為帶來細微的變更。若要完全掌控您函式所使用的相依性，請利用部署套件封裝您的所有相依性。
+ **最小化依存項目的複雜性。**偏好更簡易的框架，其可快速在[執行環境](lambda-runtime-environment.md)啟動時載入。
+ **將部署套件最小化至執行時間所必要的套件大小。**這能減少您的部署套件被下載與呼叫前解壓縮的時間。對於以 .NET 撰寫的函數，請避免上傳整個 AWS SDK 程式庫做為部署套件的一部分。或者，選擇性倚賴取得您需要的軟體開發套件元件的模組 (例如 DynamoDB、Amazon S3 開發套件模組，以及 Lambda 核心程式庫)。

**請利用執行環境重新使用來改看函式的效能。**在函式處理常式之外初始化 SDK 用戶端和資料庫連線，並在本機快取 `/tmp` 目錄中的靜態資產。由您函式的相同執行個體處理的後續叫用可以重複使用這些資源。這可藉由減少函數執行時間來節省成本。

若要避免叫用間洩漏潛在資料，請不要使用執行環境來儲存使用者資料、事件，或其他牽涉安全性的資訊。如果您的函式依賴無法存放在處理常式內記憶體中的可變狀態，請考慮為每個使用者建立個別函式或個別函式版本。

**使用 Keep-Alive 指令維持持續連線的狀態。**Lambda 會隨著時間的推移清除閒置連線。叫用函數時嘗試重複使用閒置連線將導致連線錯誤。若要維護持續連線，請使用與執行階段相關聯的 keep-alive (保持啟用) 指令。如需範例，請參閱[在 Node.js 中重複使用 Keep-Alive 的連線](https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/node-reusing-connections.html)。

**使用[環境變數](configuration-envvars.md)將操作參數傳遞給您的函數。**例如，如果您正在寫入到 Amazon S3 儲存貯體，而非對您正在寫入的儲存貯體名稱進行硬式編碼，請將儲存貯體名稱設定為環境變數。

**避免在 Lambda 函數中使用遞迴調用**，其中函數會調用自己或啟動可能再次調用函數的程序。這會導致意外的函式呼叫量與升高的成本。若您看到意外的調用數量，當更新程式碼時，請立刻將函數的預留並行設為 `0`，以調節對函數的所有調用。

**請勿在您的 Lambda 函數程式碼中使用未記錄的非公有 API**。對於 AWS Lambda 受管執行期，Lambda 會定期將安全性和功能更新套用至 Lambda 的內部 APIs。這些內部 API 更新可能是向後不相容的，這會導致意外結果，例如若您的函數依賴於這些非公有 API，則叫用失敗。請參閱 [API 參考](https://docs.aws.amazon.com/lambda/latest/api/welcome.html)查看公開可用 API 的清單。

**撰寫等冪程式碼。**為函數撰寫等冪程式碼可確保採用相同方式來處理重複事件。程式碼應正確驗證事件並正常處理重複的事件。如需詳細資訊，請參閱 [How do I make my Lambda function idempotent?](https://aws.amazon.com/premiumsupport/knowledge-center/lambda-function-idempotent/) (如何讓 Lambda 函數等冪？)。

# 使用 .zip 封存檔建置和部署 C＃ Lambda 函數
<a name="csharp-package"></a>

.NET 部署套件 (.zip 封存檔) 包含函數的編譯組件，及其所有的組件相依項。該套件也包含 `proj.deps.json` 檔案。這會對 .NET 執行期發出訊號，告知函數的所有相依項和用於設定執行期的 `proj.runtimeconfig.json` 檔案。

若要部署個別 Lambda 函數，您可以使用 `Amazon.Lambda.Tools` .NET Lambda Global CLI。若使用 `dotnet lambda deploy-function` 命令，系統會自動建立 .zip 部署套件並部署至 Lambda。不過，我們建議您使用 AWS Serverless Application Model (AWS SAM) 或 AWS Cloud Development Kit (AWS CDK)，將 .NET 應用程式部署到 AWS。

無伺服器應用程式通常包含 Lambda 函數和其他受管 AWS 服務的組合，搭配使用以執行特定業務工作。AWS SAM 和 AWS CDK 簡化了透過其他 AWS 服務大規模建置和部署 Lambda 函數的作業。[AWS SAM 範本規範](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-specification.html)提供了簡單而清晰的語法，用於描述構成無伺服器應用程式的 Lambda 函數、API、許可、組態和其他 AWS 資源。您可以使用 [AWS CDK](https://docs.aws.amazon.com/cdk/v2/guide/home.html) 將雲端基礎架構定義為程式碼，協助您運用 .NET 等現代程式設計語言，在雲端建置可靠、可擴展且經濟實惠的應用程式。AWS CDK 和 AWS SAM 都是使用 .NET Lambda Global CLI 來封裝函數。

雖然可以[使用 .NET Core CLI](csharp-package-cli.md#csharp-layers)，以 C\$1 函數使用 [Lambda 層](chapter-layers.md)，但建議不要這麼做。使用層的 C\$1 函數會在 [初始化階段](lambda-runtime-environment.md#runtimes-lifecycle-ib) 中手動載入共用組件，這可能會增加冷啟動時間。相反，在編譯時納入所有共用程式碼，避免在執行時期載入組件對效能產生影響。

如需使用 AWS SAM、AWS CDK 和 .NET Lambda Global CLI 建置和部署 .NET Lambda 函數的相關說明，請參閱以下各節。

**Topics**
+ [

# 使用 .NET Lambda Global CLI
](csharp-package-cli.md)
+ [

# 使用 AWS SAM 部署 C\$1 Lambda 函數
](csharp-package-sam.md)
+ [

# 使用 AWS CDK 部署 C\$1 Lambda 函數
](csharp-package-cdk.md)
+ [

# 部署 ASP.NET 應用程式
](csharp-package-asp.md)

# 使用 .NET Lambda Global CLI
<a name="csharp-package-cli"></a>

透過 .NET CLI 和 .NET Lambda Global Tools 延伸模組 (`Amazon.Lambda.Tools`)，可以跨平台建立 .NET 式 Lambda 應用程式、封裝這些應用程式，然後部署到 Lambda。在本節中，您將學習如何使用 .NET CLI 和 Amazon Lambda 範本建立新的 Lambda .NET 專案，以及如何使用 `Amazon.Lambda.Tools` 封裝和部署這些專案。

**Topics**
+ [

## 必要條件
](#csharp-package-cli-prerequisites)
+ [

## 使用 .NET CLI 建立 .NET 專案
](#csharp-package-cli-create)
+ [

## 使用 .NET CLI 部署 .NET 專案
](#csharp-package-cli-deploy)
+ [

## 透過 .NET CLI 使用 Lambda 層
](#csharp-layers)

## 必要條件
<a name="csharp-package-cli-prerequisites"></a>

**.NET 8 SDK**  
如果尚未安裝，請安裝 [.NET 8](https://dotnet.microsoft.com/en-us/download/dotnet/8.0) SDK 和執行時期。

**AWS Amazon.Lambda.Templates .NET 專案範本**  
若要產生 Lambda 函數程式碼，請使用 [https://www.nuget.org/packages/Amazon.Lambda.Templates](https://www.nuget.org/packages/Amazon.Lambda.Templates) NuGet 套件。若要安裝此範本套件，請執行下列命令：  

```
dotnet new install Amazon.Lambda.Templates
```

**AWS Amazon.Lambda.Tools .NET Global CLI 工具**  
若要建立 Lambda 函數，請使用 [https://www.nuget.org/packages/Amazon.Lambda.Tools](https://www.nuget.org/packages/Amazon.Lambda.Tools) [.NET Core Global Tools 延伸模組](https://aws.amazon.com/blogs/developer/net-core-global-tools-for-aws/)。若要安裝 Amazon.Lambda.Tools，請執行下列命令：  

```
dotnet tool install -g Amazon.Lambda.Tools
```
如需有關 Amazon.Lambda.Tools .NET CLI 延伸模組的詳細資訊，請參閱 GitHub 上的[適用於 .NET CLI 的 AWS 延伸模組](https://github.com/aws/aws-extensions-for-dotnet-cli)儲存庫。

## 使用 .NET CLI 建立 .NET 專案
<a name="csharp-package-cli-create"></a>

在 .NET CLI 中，在命令列中使用 `dotnet new` 命令建立 .NET 專案。Lambda 提供使用 [https://www.nuget.org/packages/Amazon.Lambda.Templates](https://www.nuget.org/packages/Amazon.Lambda.Templates) NuGet 套件的其他範本。

安裝此套件後，執行以下命令即可查看可用範本的清單。

```
dotnet new list
```

若要檢查範本的詳細資訊，請使用 `help` 選項。例如，若要查看有關 `lambda.EmptyFunction` 範本的詳細資訊，請執行以下命令。

```
dotnet new lambda.EmptyFunction --help
```

若要建立 .NET Lambda 函數的基本範本，請使用 `lambda.EmptyFunction` 範本。這會建立一個簡單的函數，此函數會接受字串作為輸入，並使用 `ToUpper` 方法轉換為大寫。此範本支援以下選項︰ 
+ `--name` - 函數的名稱。
+ `--region`：要建立函數的 AWS 區域。
+ `--profile`：您的 適用於 .NET 的 AWS SDK 憑證檔中的設定檔名稱。若要深入了解 .NET 中的憑證設定檔，請參閱**《適用於 .NET 的 AWS SDK 開發人員指南》中的[設定 AWS 憑證](https://docs.aws.amazon.com/sdk-for-net/v3/developer-guide/net-dg-config-creds.html)。

在此範例中，我們使用預設設定檔和 AWS 區域 設定建立了新的空函數 `myDotnetFunction`：

```
dotnet new lambda.EmptyFunction --name myDotnetFunction
```

此命令會在您的專案目錄中建立以下檔案和目錄。

```
└── myDotnetFunction
    ├── src
    │   └── myDotnetFunction
    │       ├── Function.cs
    │       ├── Readme.md
    │       ├── aws-lambda-tools-defaults.json
    │       └── myDotnetFunction.csproj
    └── test
        └── myDotnetFunction.Tests
            ├── FunctionTest.cs
            └── myDotnetFunction.Tests.csproj
```

在 `src/myDotnetFunction` 目錄下，檢查下列檔案：
+ **aws-lambda-tools-defaults.json**：您在部署 Lambda 函數時，在此檔案中指定命令列選項。例如：

  ```
    "profile" : "default",
    "region" : "us-east-2",
    "configuration" : "Release",
    "function-architecture": "x86_64",
    "function-runtime":"dotnet8",
    "function-memory-size" : 256,
    "function-timeout" : 30,
    "function-handler" : "myDotnetFunction::myDotnetFunction.Function::FunctionHandler"
  ```
+ **Function.cs**：您的 Lambda 處理常式函數程式碼。它是 C\$1 範本，包含了預設的 `Amazon.Lambda.Core` 程式庫和預設的 `LambdaSerializer` 屬性。如需關於序列化需求及選項的詳細資訊，請參閱[C\$1 Lambda 函式中的序列化](csharp-handler.md#csharp-handler-serializer)。它也包含可編輯以套用 Lambda 函數程式碼的範例函數。

  ```
  using Amazon.Lambda.Core;
  
  // Assembly attribute to enable the Lambda function's JSON input to be converted into a .NET class.
  [assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))]
  
  namespace myDotnetFunction;
  
  public class Function
  {
  
      /// <summary>
      /// A simple function that takes a string and does a ToUpper
      /// </summary≫
      /// <param name="input"></param>
      /// <param name="context"></param>
      /// <returns></returns>
      public string FunctionHandler(string input, ILambdaContext context)
      {
          return input.ToUpper();
      }
  }
  ```
+ **myDotnetFunction.csproj**：[MSBuild](https://msdn.microsoft.com/en-us/library/dd393574.aspx) 檔案，列出構成應用程式的檔案和組件。

  ```
  <Project Sdk="Microsoft.NET.Sdk">
    <PropertyGroup>
      <TargetFramework>net8.0</TargetFramework>
      <ImplicitUsings>enable</ImplicitUsings>
      <Nullable>enable</Nullable>
      <GenerateRuntimeConfigurationFiles>true</GenerateRuntimeConfigurationFiles>
      <AWSProjectType>Lambda</AWSProjectType>
      <!-- This property makes the build directory similar to a publish directory and helps the AWS .NET Lambda Mock Test Tool find project dependencies. -->
      <CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
      <!-- Generate ready to run images during publishing to improve cold start time. -->
      <PublishReadyToRun>true</PublishReadyToRun>
    </PropertyGroup>
    <ItemGroup>
      <PackageReference Include="Amazon.Lambda.Core" Version="2.2.0" />
      <PackageReference Include="Amazon.Lambda.Serialization.SystemTextJson" Version="2.4.0" />
    </ItemGroup>
  </Project>
  ```
+ **Readme**：使用此檔案來記錄您的 Lambda 函數。

在 `myfunction/test` 目錄下，檢查下列檔案：
+ **myDotnetFunction.Tests.csproj**：如上所述，這是 [MSBuild](https://msdn.microsoft.com/en-us/library/dd393574.aspx) 檔案，其列出了構成您的測試專案的檔案和組件。也請注意，它包含 `Amazon.Lambda.Core` 程式庫，以便您順利整合測試函數時所需要的任何 Lambda 範本。

  ```
  <Project Sdk="Microsoft.NET.Sdk">
     ... 
  
      <PackageReference Include="Amazon.Lambda.Core" Version="2.2.0 " />
     ...
  ```
+ **FunctionTest.cs**：包含在 `src` 目錄中的相同的 C\$1 程式碼範本檔案。編輯此檔案以鏡像您的函數的生產程式碼，並在上傳 Lambda 函數至生產環境之前進行測試。

  ```
  using Xunit;
  using Amazon.Lambda.Core;
  using Amazon.Lambda.TestUtilities;
  
  using MyFunction;
  
  namespace MyFunction.Tests
  {
      public class FunctionTest
      {
          [Fact]
          public void TestToUpperFunction()
          {
  
              // Invoke the lambda function and confirm the string was upper cased.
              var function = new Function();
              var context = new TestLambdaContext();
              var upperCase = function.FunctionHandler("hello world", context);
  
              Assert.Equal("HELLO WORLD", upperCase);
          }
      }
  }
  ```

## 使用 .NET CLI 部署 .NET 專案
<a name="csharp-package-cli-deploy"></a>

若要建置部署套件並部署到 Lambda，請使用 `Amazon.Lambda.Tools` CLI 工具。若要從先前步驟中建立的檔案部署函數，請先瀏覽至包含函數 `.csproj` 檔案的資料夾。

```
cd myDotnetFunction/src/myDotnetFunction
```

若要將程式碼以 .zip 部署套件形式部署至 Lambda，請執行下列命令。選擇您的函數名稱。

```
dotnet lambda deploy-function myDotnetFunction
```

在部署期間，精靈會要求您選取 [使用執行角色定義 Lambda 函數許可](lambda-intro-execution-role.md)。在此範例中，請選取 `lambda_basic_role`。

部署函數後，您可以使用 `dotnet lambda invoke-function` 命令在雲端進行測試。在 `lambda.EmptyFunction` 範本的程式碼範例中，您可以使用 `--payload` 選項傳入字串來測試函數。

```
dotnet lambda invoke-function myDotnetFunction --payload "Just checking if everything is OK"
```

如果函數部署成功，您應該會看到類似以下內容的輸出。

```
dotnet lambda invoke-function myDotnetFunction --payload "Just checking if everything is OK"
Amazon Lambda Tools for .NET Core applications (5.8.0)
Project Home: https://github.com/aws/aws-extensions-for-dotnet-cli, https://github.com/aws/aws-lambda-dotnet

Payload:
"JUST CHECKING IF EVERYTHING IS OK"

Log Tail:
START RequestId: id Version: $LATEST
END RequestId: id
REPORT RequestId: id  Duration: 0.99 ms       Billed Duration: 1 ms         Memory Size: 256 MB     Max Memory Used: 12 MB
```

## 透過 .NET CLI 使用 Lambda 層
<a name="csharp-layers"></a>

**注意**  
雖然在 .NET 中可以將[層](chapter-layers.md)與函式搭配使用，但建議不要這麼做。.NET 中使用層的函式會在 `Init` 階段手動將共用組件載入到記憶體中，這可能會增加冷啟動時間。請改在編譯時加入所有共用程式碼，利用 .NET 編譯器的內建最佳化功能。

.NET CLI 支援命令，協助您發布層及部署使用層的 C\$1 函數。若要將層發布至指定的 Amazon S3 儲存貯體，請在與 `.csproj` 檔案相同的目錄中執行以下命令：

```
dotnet lambda publish-layer <layer_name> --layer-type runtime-package-store --s3-bucket <s3_bucket_name>
```

接著使用 .NET CLI 部署函數時，請在以下命令中指定要使用的層 ARN：

```
dotnet lambda deploy-function <function_name> --function-layers arn:aws:lambda:us-east-1:123456789012:layer:layer-name:1
```

如需 Hello World 函數的完整範例，請參閱 [blank-csharp-with-layer](https://github.com/awsdocs/aws-lambda-developer-guide/tree/main/sample-apps/blank-csharp-with-layer) 範例。

# 使用 AWS SAM 部署 C\$1 Lambda 函數
<a name="csharp-package-sam"></a>

AWS Serverless Application Model(AWS SAM) 是一項工具組，可協助簡化在 AWS 上建置和執行無伺服器應用程式的程序。您可以在 YAML 或 JSON 範本中定義應用程式的資源，並使用 AWS SAM 命令列界面 (AWS SAM CLI) 來建置、封裝及部署應用程式。使用 AWS SAM 範本建置 Lambda 函數時，AWS SAM 會使用函數程式碼和您指定的任何相依項，自動建立 .zip 部署套件或容器映像檔。接著 AWS SAM 會使用 [CloudFormation 堆疊](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/stacks.html)部署函數。若要進一步了解如何使用 AWS SAM 建置和部署 Lambda 函數，請參閱*《AWS Serverless Application Model 開發人員指南》*中的 [AWS SAM入門](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-getting-started.html)。

下列步驟說明如何使用 AWS SAM 來下載、建置和部署範例 .NET Hello World 應用程式。此範例應用程式使用 Lambda 函數和 Amazon API Gateway 端點來實作基本 API 後端。當您傳送 HTTP GET 請求至 API Gateway 端點時，API Gateway 端點會調用您的 Lambda 函數。此函數會傳回「hello world」訊息，以及處理您請求之 Lambda 函數執行個體的 IP 地址。

當您使用 AWS SAM 建置和部署應用程式時，AWS SAM CLI 會在背景使用 `dotnet lambda package` 命令封裝個別 Lambda 函數程式碼套件。

## 必要條件
<a name="csharp-package-sam-prerequisites"></a>

**.NET 8 SDK**  
安裝 [.NET 8](https://dotnet.microsoft.com/en-us/download/dotnet/8.0) SDK 和執行時期。

**AWS SAM CLI 1.39 版或更新版本**  
若要了解如何安裝最新版 AWS SAM CLI，請參閱[安裝 AWS SAM CLI](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/install-sam-cli.html)。

## 部署範例 AWS SAM 應用程式
<a name="csharp-package-sam-deploy"></a>

1. 使用以下命令，初始化使用 Hello world .NET 範本的應用程式。

   ```
   sam init --app-template hello-world --name sam-app \
   --package-type Zip --runtime dotnet8
   ```

   此命令會在您的專案目錄中建立以下檔案和目錄。

   ```
   └── sam-app
       ├── README.md
       ├── events
       │   └── event.json
       ├── omnisharp.json
       ├── samconfig.toml
       ├── src
       │   └── HelloWorld
       │       ├── Function.cs
       │       ├── HelloWorld.csproj
       │       └── aws-lambda-tools-defaults.json
       ├── template.yaml
       └── test
           └── HelloWorld.Test
               ├── FunctionTest.cs
               └── HelloWorld.Tests.csproj
   ```

1. 瀏覽至包含 `template.yaml file` 的目錄。此檔案是為應用程式定義 AWS 資源的範本，包括 Lambda 函數和 API Gateway API。

   ```
   cd sam-app
   ```

1. 若要建置應用程式的原始碼，請執行下列命令。

   ```
   sam build
   ```

1. 若要將應用程式部署至 AWS，請執行下列命令。

   ```
   sam deploy --guided
   ```

   此命令會透過下列一系列提示封裝並部署應用程式。若要接受預設選項，請按 Enter。
**注意**  
若顯示 **HelloWorldFunction 可能未定義授權，仍要繼續嗎?**，請務必輸入 `y`。
   + **堆疊名稱**：要部署至 CloudFormation 的堆疊名稱。此名稱對您的 AWS 帳戶和 AWS 區域而言都必須是唯一的。
   + **AWS 區域**：您想要部署應用程式的目標 AWS 區域。
   + **部署前確認變更**：選取是，即可在 AWS SAM 部署應用程式變更之前手動檢閱任何變更集。如果選取否，AWS SAM CLI 會自動部署應用程式變更。
   + **允許建立 SAM CLI IAM 角色**：許多 AWS SAM 範本 (包括本範例中的 Hello world 範本) 都會建立 AWS Identity and Access Management (IAM) 角色，以授予 Lambda 函數存取其他 AWS 服務 的許可。選取「是」以提供許可，允許部署建立或修改 IAM 角色的 CloudFormation 堆疊。
   + **停用復原**：依照預設，如果在建立或部署堆疊期間 AWS SAM 發生錯誤，便會將堆疊復原至先前的版本。選取「否」以接受此預設設定。
   + **HelloWorldFunction 可能未定義授權，仍要繼續嗎**：請輸入 `y`。
   + **將引數儲存至 samconfig.toml**：選取是以儲存您選擇的組態。您之後可以在沒有參數的情況下重新執行 `sam deploy`，以將變更部署到應用程式。

1. 應用程式部署完成後，CLI 會傳回 Hello World Lambda 函數的 Amazon Resource Name (ARN)，以及為應用程式建立的 IAM 角色。此外也會顯示您的 API Gateway API 端點。若要測試應用程式，請在瀏覽器中開啟端點。您應該會看到類似以下內容的回應。

   ```
   {"message":"hello world","location":"34.244.135.203"}
   ```

1. 若要刪除資源，請執行下列命令。請注意，您建立的 API 端點，是可以透過網際網路存取的公有端點。建議您在測試後刪除此端點。

   ```
   sam delete
   ```

## 後續步驟
<a name="csharp-package-sam-next"></a>

若要進一步了解使用 AWS SAM 來建置和部署使用 .NET 的 Lambda 函數，請參閱下列資源：
+ [https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/what-is-sam.html](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/what-is-sam.html)
+ [使用 AWS Lambda 和 SAM CLI 建置無伺服器 .NET 應用程式](https://aws.amazon.com/blogs/dotnet/building-serverless-net-applications-with-aws-lambda-and-the-sam-cli/)

# 使用 AWS CDK 部署 C\$1 Lambda 函數
<a name="csharp-package-cdk"></a>

AWS Cloud Development Kit (AWS CDK) 是開放原始碼軟體開發架構，用於透過現代程式設計語言和 .NET 等架構，將雲端基礎架構定義為程式碼。系統會執行 AWS CDK 專案以產生 CloudFormation 範本，然後用來部署程式碼。

若要使用 AWS CDK 建置和部署範例 Hello world .NET 應用程式，請依照下列各節的指示操作。範例應用程式會實作基本 API 後端 (包含 API Gateway 端點和 Lambda 函數)。當您傳送 HTTP GET 請求至端點時，API Gateway 會調用 Lambda 函數 此函數會傳回 Hello world 訊息，以及處理您請求之 Lambda 執行個體的 IP 地址。

## 必要條件
<a name="csharp-package-cdk-prereqs"></a>

**.NET 8 SDK**  
安裝 [.NET 8](https://dotnet.microsoft.com/en-us/download/dotnet/8.0) SDK 和執行時期。

**AWS CDK 第 2 版**  
若要了解如何安裝最新版本的 AWS CDK，請參閱《AWS Cloud Development Kit (AWS CDK) v2 開發人員指南》**中的[開始使用 AWS CDK](https://docs.aws.amazon.com/cdk/v2/guide/getting_started.html)。

## 部署範例 AWS CDK 應用程式
<a name="csharp-package-cdk-deploy"></a>

1. 為範例應用程式建立專案目錄，並瀏覽至該目錄。

   ```
   mkdir hello-world
   cd hello-world
   ```

1. 執行下列命令以初始化新的 AWS CDK 應用程式。

   ```
   cdk init app --language csharp
   ```

   此命令會在您的專案目錄中建立以下檔案和目錄

   ```
   ├── README.md
   ├── cdk.json
   └── src
       ├── HelloWorld
       │   ├── GlobalSuppressions.cs
       │   ├── HelloWorld.csproj
       │   ├── HelloWorldStack.cs
       │   └── Program.cs
       └── HelloWorld.sln
   ```

1. 開啟 `src` 目錄，並使用 .NET CLI 建立新的 Lambda 函數。這是您將使用 AWS CDK 部署的功能。在此範例中，您將使用 `lambda.EmptyFunction` 範本建立名為 `HelloWorldLambda` 的 Hello world 函數。

   ```
   cd src
   dotnet new lambda.EmptyFunction -n HelloWorldLambda
   ```

   完成此步驟後，專案目錄中的目錄結構應如下所示。

   ```
   ├── README.md
   ├── cdk.json
   └── src
       ├── HelloWorld
       │   ├── GlobalSuppressions.cs
       │   ├── HelloWorld.csproj
       │   ├── HelloWorldStack.cs
       │   └── Program.cs
       ├── HelloWorld.sln
       └── HelloWorldLambda
           ├── src
           │   └── HelloWorldLambda
           │       ├── Function.cs
           │       ├── HelloWorldLambda.csproj
           │       ├── Readme.md
           │       └── aws-lambda-tools-defaults.json
           └── test
               └── HelloWorldLambda.Tests
                   ├── FunctionTest.cs
                   └── HelloWorldLambda.Tests.csproj
   ```

1. 在 `src/HelloWorld` 目錄中，開啟 `HelloWorldStack.cs` 檔案。將檔案的內容取代為下列程式碼。

   ```
   using Amazon.CDK;
   using Amazon.CDK.AWS.Lambda;
   using Amazon.CDK.AWS.Logs;
   using Constructs;
   
   namespace CdkTest
   {
       public class HelloWorldStack : Stack
       {
           internal HelloWorldStack(Construct scope, string id, IStackProps props = null) : base(scope, id, props)
           {
               var buildOption = new BundlingOptions()
               {
                   Image = Runtime.DOTNET_8.BundlingImage,
                   User = "root",
                   OutputType = BundlingOutput.ARCHIVED,
                   Command = new string[]{
               "/bin/sh",
                   "-c",
                   " dotnet tool install -g Amazon.Lambda.Tools"+
                   " && dotnet build"+
                   " && dotnet lambda package --output-package /asset-output/function.zip"
                   }
               };
   
                var helloWorldLambdaFunction = new Function(this, "HelloWorldFunction", new FunctionProps
               {
                   Runtime = Runtime.DOTNET_8,
                   MemorySize = 1024,
                   LogRetention = RetentionDays.ONE_DAY,
                   Handler = "HelloWorldLambda::HelloWorldLambda.Function::FunctionHandler",
                   Code = Code.FromAsset("./src/HelloWorldLambda/src/HelloWorldLambda", new Amazon.CDK.AWS.S3.Assets.AssetOptions
                   {
                       Bundling = buildOption
                   }),
               });
           }
       }
   }
   ```

   這個程式碼是用來編譯和綁定應用程式程式碼，以及 Lambda 函數本身的定義。`BundlingOptions` 物件可建立一個 zip 檔及一組用於產生 zip 檔內容的命令。在此情況中，`dotnet lambda package` 命令用於編譯和產生 zip 檔。

1. 若要部署應用程式，請執行下列命令。

   ```
   cdk deploy
   ```

1. 使用 .NET Lambda CLI 調用已部署的 Lambda 函數。

   ```
   dotnet lambda invoke-function HelloWorldFunction -p "hello world"
   ```

1. 完成測試後，除非您想要保留建立的資源，否則可直接刪除。若要刪除資源，請執行下列命令。

   ```
   cdk destroy
   ```

## 後續步驟
<a name="csharp-package-cdk-next"></a>

若要進一步了解使用 AWS CDK 來建置和部署使用 .NET 的 Lambda 函數，請參閱下列資源：
+ [以 C\$1 使用 AWS CDK](https://docs.aws.amazon.com/cdk/v2/guide/work-with-cdk-csharp.html)
+ [使用 AWS CDK 建置、封裝和發布 .NET C\$1 Lambda 函數](https://aws.amazon.com/blogs/modernizing-with-aws/build-package-publish-dotnet-csharp-lambda-functions-aws-cdk/)

# 部署 ASP.NET 應用程式
<a name="csharp-package-asp"></a>

除了託管事件驅動型函數之外，您還可以搭配使用 .NET 與 Lambda 來託管輕量型 ASP.NET 應用程式。您可以使用 `Amazon.Lambda.AspNetCoreServer` NuGet 套件來建置和部署 ASP.NET 應用程式。在本節中，您將了解如何使用 .NET Lambda CLI 工具，將 ASP.NET Web API 部署至 Lambda。

**Topics**
+ [

## 必要條件
](#csharp-package-asp-prerequisites)
+ [

## 將 ASP.NET Web API 部署到 Lambda
](#csharp-package-asp-deploy-api)
+ [

## 將 ASP.NET Minimal API 部署到 Lambda
](#csharp-package-asp-deploy-minimal)

## 必要條件
<a name="csharp-package-asp-prerequisites"></a>

**.NET 8 SDK**  
安裝 [.NET 8](https://dotnet.microsoft.com/en-us/download/dotnet/8.0) SDK 和 ASP.NET Core 執行時期。

**Amazon.Lambda.Tools**  
若要建立 Lambda 函數，請使用 [https://www.nuget.org/packages/Amazon.Lambda.Tools](https://www.nuget.org/packages/Amazon.Lambda.Tools) [.NET Core Global Tools 延伸模組](https://aws.amazon.com/blogs/developer/net-core-global-tools-for-aws/)。若要安裝 Amazon.Lambda.Tools，請執行下列命令：  

```
dotnet tool install -g Amazon.Lambda.Tools
```
如需有關 Amazon.Lambda.Tools .NET CLI 延伸模組的詳細資訊，請參閱 GitHub 上的[適用於 .NET CLI 的 AWS 延伸模組](https://github.com/aws/aws-extensions-for-dotnet-cli)儲存庫。

**Amazon.Lambda.Templates**  
若要產生 Lambda 函數程式碼，請使用 [https://www.nuget.org/packages/Amazon.Lambda.Templates](https://www.nuget.org/packages/Amazon.Lambda.Templates) NuGet 套件。若要安裝此範本套件，請執行下列命令：  

```
dotnet new --install Amazon.Lambda.Templates
```

## 將 ASP.NET Web API 部署到 Lambda
<a name="csharp-package-asp-deploy-api"></a>

若要使用 ASP.NET 部署 Web API，您可以使用 .NET Lambda 範本建立新的 Web API 專案。使用下列命令來初始化新的 ASP.NET Web API 專案。在範例命令中，我們將專案命名為 `AspNetOnLambda`。

```
dotnet new serverless.AspNetCoreWebAPI -n AspNetOnLambda
```

此命令會在您的專案目錄中建立以下檔案和目錄。

```
.
└── AspNetOnLambda
    ├── src
    │   └── AspNetOnLambda
    │       ├── AspNetOnLambda.csproj
    │       ├── Controllers
    │       │   └── ValuesController.cs
    │       ├── LambdaEntryPoint.cs
    │       ├── LocalEntryPoint.cs
    │       ├── Readme.md
    │       ├── Startup.cs
    │       ├── appsettings.Development.json
    │       ├── appsettings.json
    │       ├── aws-lambda-tools-defaults.json
    │       └── serverless.template
    └── test
        └── AspNetOnLambda.Tests
            ├── AspNetOnLambda.Tests.csproj
            ├── SampleRequests
            │   └── ValuesController-Get.json
            ├── ValuesControllerTests.cs
            └── appsettings.json
```

當 Lambda 調用函數時，使用的進入點就是 `LambdaEntryPoint.cs` 檔案。.NET Lambda 範本建立的檔案包含下列程式碼。

```
namespace AspNetOnLambda;

public class LambdaEntryPoint : Amazon.Lambda.AspNetCoreServer.APIGatewayProxyFunction
{
    protected override void Init(IWebHostBuilder builder)
    {
        builder
            .UseStartup≪Startup≫();
    }

    protected override void Init(IHostBuilder builder)
    {
    }
}
```

Lambda 使用的進入點，必須繼承自 `Amazon.Lambda.AspNetCoreServer` 套件中三個基本類別的其中一個。這三個基本類別為：
+ `APIGatewayProxyFunction`
+ `APIGatewayHttpApiV2ProxyFunction`
+ `ApplicationLoadBalancerFunction`

當您使用提供的 .NET Lambda 範本建立 `LambdaEntryPoint.cs` 檔案時，所使用的預設類別為 `APIGatewayProxyFunction`。您在函數中使用的基本類別，取決於位於 Lambda 函數前的 API 層。

三個基本類別都包含名為 `FunctionHandlerAsync` 的公有方法。Lambda 用來調用函數的[處理常式字串](csharp-handler.md#csharp-class-library-handlers)中，會包含此方法的名稱。`FunctionHandlerAsync` 方法會將輸入事件承載轉換為正確的 ASP.NET 格式，並將 ASP.NET 回應轉換回 Lambda 回應承載。在顯示的範例 `AspNetOnLambda` 專案中，處理常式字串如下所示。

```
AspNetOnLambda::AspNetOnLambda.LambdaEntryPoint::FunctionHandlerAsync
```

若要將 API 部署至 Lambda，請執行下列命令，瀏覽至包含原始程式碼檔案的目錄，並使用 CloudFormation 部署函數。

```
cd AspNetOnLambda/src/AspNetOnLambda
dotnet lambda deploy-serverless
```

**提示**  
當您使用 `dotnet lambda deploy-serverless` 命令部署 API 時，CloudFormation 會根據您在部署期間指定的堆疊名稱，為 Lambda 函數命名。若要為 Lambda 函數提供自訂名稱，請編輯 `serverless.template` 檔案，將 `FunctionName` 屬性新增至 `AWS::Serverless::Function` 資源。如需進一步了解，請參閱《CloudFormation 使用者指南》中的[名稱類型](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-name.html)。**

## 將 ASP.NET Minimal API 部署到 Lambda
<a name="csharp-package-asp-deploy-minimal"></a>

若要將 ASP.NET Minimal API 部署到 Lambda，您可以使用 .NET Lambda 範本建立新的 Minimal API 專案。使用下列命令來初始化新的 Minimal API 專案。在此範例中，我們將專案命名為 `MinimalApiOnLambda`。

```
dotnet new serverless.AspNetCoreMinimalAPI -n MinimalApiOnLambda
```

此命令會在您的專案目錄中建立以下檔案和目錄。

```
└── MinimalApiOnLambda
    └── src
        └── MinimalApiOnLambda
            ├── Controllers
            │   └── CalculatorController.cs
            ├── MinimalApiOnLambda.csproj
            ├── Program.cs
            ├── Readme.md
            ├── appsettings.Development.json
            ├── appsettings.json
            ├── aws-lambda-tools-defaults.json
            └── serverless.template
```

`Program.cs` 檔案包含下列程式碼。

```
var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddControllers();

// Add AWS Lambda support. When application is run in Lambda Kestrel is swapped out as the web server with Amazon.Lambda.AspNetCoreServer. This
// package will act as the webserver translating request and responses between the Lambda event source and ASP.NET Core.
builder.Services.AddAWSLambdaHosting(LambdaEventSource.RestApi);

var app = builder.Build();


app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();

app.MapGet("/", () => "Welcome to running ASP.NET Core Minimal API on AWS Lambda");

app.Run();
```

若要將 Minimal API 設為在 Lambda 上執行，您可能需要編輯此程式碼，讓 Lambda 和 ASP.NET Core 之間的請求和回應能正確轉譯。根據預設，函數會針對 REST API 事件來源加以設定。若使用 HTTP API 或 Application Load Balancer，請以下列其中一個選項取代 `(LambdaEventSource.RestApi)`：
+ `(LambdaEventSource.HttpAPi)`
+ `(LambdaEventSource.ApplicationLoadBalancer)`

若要將 API 部署至 Lambda，請執行下列命令，瀏覽至包含原始程式碼檔案的目錄，並使用 CloudFormation 部署函數。

```
cd MinimalApiOnLambda/src/MinimalApiOnLambda
dotnet lambda deploy-serverless
```

# 使用 .NET Lambda 函式層
<a name="dotnet-layers"></a>

我們不建議使用[層](chapter-layers.md)來管理在 .NET 中編寫的 Lambda 函式的相依項。由於 .NET 是編譯型語言，因此函式仍須在 [Init](lambda-runtime-environment.md#runtimes-lifecycle-ib) 階段將所有共用組件手動載入記憶體中，這可能會增加冷啟動時間。使用層不僅會使部署程序複雜化，還會阻礙您利用內建編譯器最佳化功能。

若要在 .NET 處理常式中使用外部相依項，請在編譯時直接將其納入部署套件。如此一來，您既能簡化部署程序，又能利用內建的 .NET 編譯器最佳化功能。如需如何在函式中匯入與使用 NuGet 等相依項的範例，請參閱[定義 C\$1 格式的 Lambda 函數處理常式](csharp-handler.md)。

# 使用容器映像部署 .NET Lambda 函數
<a name="csharp-image"></a>

您可以透過三種方式為 .NET Lambda 函數建置容器映像：
+ [使用 .NET AWS 的基礎映像](#csharp-image-instructions)

  [AWS  基礎映像](images-create.md#runtimes-images-lp)會預先載入語言執行期、用來管理 Lambda 與函數程式碼之間互動的執行期界面用戶端，以及用於本機測試的執行期界面模擬器。
+ [使用僅限 AWS 作業系統的基礎映像](images-create.md#runtimes-images-provided)

  [AWS 僅限作業系統的基礎映像](https://gallery.ecr.aws/lambda/provided)包含 Amazon Linux 發行版本和[執行時間界面模擬器](https://github.com/aws/aws-lambda-runtime-interface-emulator/)。這些映像常用於為編譯語言 (如 [Go](go-image.md#go-image-provided) 和 [Rust](lambda-rust.md)) 和 Lambda 不提供基礎映像的語言或語言版本 (如 Node.js 19) 建置容器映像。您還可以使用僅限作業系統的基礎映像來實作[自訂執行期](runtimes-custom.md)。若要使映像檔與 Lambda 相容，您必須在映像中加入 [適用於 .NET 的執行期介面用戶端](#csharp-image-clients)。
+ [使用非AWS 基礎映像](#csharp-image-clients)

  您可以使用其他容器登錄檔中的替代基礎映像 (例如 Alpine Linux 或 Debian)。您也可以使用組織建立的自訂映像。若要使映像檔與 Lambda 相容，您必須在映像中加入 [適用於 .NET 的執行期介面用戶端](#csharp-image-clients)。

**提示**  
若要縮短 Lambda 容器函數變成作用中狀態所需的時間，請參閱 Docker 文件中的[使用多階段建置](https://docs.docker.com/build/building/multi-stage/)。若要建置有效率的容器映像，請遵循[撰寫 Dockerfiles 的最佳實務](https://docs.docker.com/develop/develop-images/dockerfile_best-practices/)。

本頁面會說明如何為 Lambda 建置、測試和部署容器映像。

**Topics**
+ [

## AWS .NET 的基礎映像
](#csharp-image-base)
+ [

## 使用 .NET AWS 的基礎映像
](#csharp-image-instructions)
+ [

## 透過執行期介面用戶端使用替代基礎映像
](#csharp-image-clients)

## AWS .NET 的基礎映像
<a name="csharp-image-base"></a>

AWS 為 .NET 提供下列基礎映像：


| Tags (標籤) | 執行期 | 作業系統 | Dockerfile | 棄用 | 
| --- | --- | --- | --- | --- | 
| 10 | .NET 10 | Amazon Linux 2023 | [GitHub 上適用於 .NET 10 的 Dockerfile](https://github.com/aws/aws-lambda-base-images/blob/dotnet10/Dockerfile.dotnet10) |   2028 年 11 月 14 日   | 
| 9 | .NET 9 | Amazon Linux 2023 | [GitHub 上適用於 .NET 9 的 Dockerfile](https://github.com/aws/aws-lambda-base-images/blob/dotnet9/Dockerfile.dotnet9) |   2026 年 11 月 10 日   | 
| 8 | .NET 8 | Amazon Linux 2023 | [Dockerfile for .NET 8 on GitHub](https://github.com/aws/aws-lambda-base-images/blob/dotnet8/Dockerfile.dotnet8) |   2026 年 11 月 10 日   | 

Amazon ECR 儲存庫︰[gallery.ecr.aws/lambda/dotnet](https://gallery.ecr.aws/lambda/dotnet)

## 使用 .NET AWS 的基礎映像
<a name="csharp-image-instructions"></a>

### 先決條件
<a name="dotnet-csharp-image-prerequisites"></a>

若要完成本節中的步驟，您必須執行下列各項：
+ [.NET SDK](https://dotnet.microsoft.com/download) – 下列步驟使用 .NET 8 基礎映像。確保您的 .NET 版本與您在 Dockerfile 中指定的[基礎映像](https://gallery.ecr.aws/lambda/dotnet)的版本相符。
+ [Docker](https://docs.docker.com/get-docker) (最低版本 25.0.0)
+ Docker [buildx 外掛程式](https://github.com/docker/buildx/blob/master/README.md)。

### 使用基礎映像建立和部署映像
<a name="dotnet-image-create"></a>

在下面的步驟中，您可以使用 [Amazon.Lambda.Templates](https://github.com/aws/aws-lambda-dotnet#dotnet-cli-templates) 和 [Amazon.Lambda.Tools](https://github.com/aws/aws-extensions-for-dotnet-cli#aws-lambda-amazonlambdatools) 來建立 .NET 專案。然後，您可以建置 Docker 映像檔，將該映像檔上傳到 Amazon ECR，然後將其部署到 Lambda 函數。

1. 安裝 [Amazon.Lambda.Templates](https://github.com/aws/aws-lambda-dotnet#dotnet-cli-templates) NuGet 套件。

   ```
   dotnet new install Amazon.Lambda.Templates
   ```

1. 使用 `lambda.image.EmptyFunction` 範本建立 .NET 專案。

   ```
   dotnet new lambda.image.EmptyFunction --name MyFunction --region us-east-1
   ```

   專案檔案儲存在 `MyFunction/src/MyFunction` 目錄中：
   + **aws-lambda-tools-defaults.json**：指定用於部署 Lambda 函式的命令列選項。
   + **Function.cs**：您的 Lambda 處理常式函數程式碼。這是 C\$1 範本，包含了預設的 `Amazon.Lambda.Core` 程式庫和預設的 `LambdaSerializer` 屬性。如需有關序列化需求及選項的詳細資訊，請參閱 [C\$1 Lambda 函式中的序列化](csharp-handler.md#csharp-handler-serializer)。可以使用提供的程式碼進行測試，也可以將其替換為您自己的程式碼。
   + **MyFunction.csproj** – .NET [專案檔案](https://learn.microsoft.com/en-us/dotnet/core/project-sdk/overview#project-files)，列出了構成應用程式的檔案與組件。
   + **Dockerfile**：您可以使用提供的 Dockerfile 進行測試，也可以將其取代為自訂的 Dockerfile。如果使用自己的，請確保：
     + 將 `FROM` 屬性設定為[基礎映像的 URI](https://gallery.ecr.aws/lambda/dotnet)。基礎映像和 `MyFunction.csproj` 檔案中的 `TargetFramework` 都必須使用相同的 .NET 版本。例如，若要使用 .NET 9：
       + Dockerfile：`FROM public.ecr.aws/lambda/dotnet:9`
       + MyFunction.csproj：`<TargetFramework>net9.0</TargetFramework>`
     + 將 `CMD` 引數設定為 Lambda 函數處理常式。這應符合 `aws-lambda-tools-defaults.json` 中的 `image-command`。

1. 安裝 Amazon.Lambda.Tools [.NET Global Tool](https://aws.amazon.com/blogs/developer/net-core-global-tools-for-aws/)。

   ```
   dotnet tool install -g Amazon.Lambda.Tools
   ```

   如果已安裝 Amazon.Lambda.Tools，則請確保您有最新版本。

   ```
   dotnet tool update -g Amazon.Lambda.Tools
   ```

1. 如果您尚未這麼做，請將目錄變更為 `MyFunction/src/MyFunction`。

   ```
   cd src/MyFunction
   ```

1. 使用 Amazon.Lambda.Tools 建置 Docker 映像檔，將其推送至新的 Amazon ECR 儲存庫，然後部署 Lambda 函數。

   對於 `--function-role`，指定函數[執行角色](lambda-intro-execution-role.md)的角色名稱 (而非 Amazon Resource Name (ARN))。例如 `lambda-role`。

   ```
   dotnet lambda deploy-function MyFunction --function-role lambda-role
   ```

   如需有關 Amazon.Lambda.Tools .NET Global Tool 的詳細資訊，請參閱 GitHub 上的 [.NET CLI 的AWS 延伸模組](https://github.com/aws/aws-extensions-for-dotnet-cli)儲存庫。

1. 調用函數。

   ```
   dotnet lambda invoke-function MyFunction --payload "Testing the function"
   ```

   如果一切順利，您會看到類似如下內容的回應：

   ```
   Payload:
   {"Lower":"testing the function","Upper":"TESTING THE FUNCTION"}
   
   Log Tail:
   INIT_REPORT Init Duration: 9999.81 ms   Phase: init     Status: timeout
   START RequestId: 12378346-f302-419b-b1f2-deaa1e8423ed Version: $LATEST
   END RequestId: 12378346-f302-419b-b1f2-deaa1e8423ed
   REPORT RequestId: 12378346-f302-419b-b1f2-deaa1e8423ed  Duration: 3173.06 ms    Billed Duration: 3174 ms        Memory Size: 512 MB     Max Memory Used: 24 MB
   ```

1. 刪除 Lambda 函數。

   ```
   dotnet lambda delete-function MyFunction
   ```

## 透過執行期介面用戶端使用替代基礎映像
<a name="csharp-image-clients"></a>

如果您使用[僅限作業系統的基礎映像](images-create.md#runtimes-images-provided)或替代的基礎映像，則必須在映像中加入執行期介面用戶端。執行期介面用戶端會讓您擴充 [Runtime API](runtimes-api.md)，管理 Lambda 與函數程式碼之間的互動。

下列範例示範如何使用非AWS 基礎映像為 .NET 建置容器映像，以及如何新增 [Amazon.Lambda.RuntimeSupport 套件](https://github.com/aws/aws-lambda-dotnet/blob/master/Libraries/src/Amazon.Lambda.RuntimeSupport/README.md#using-amazonlambdaruntimesupport-as-a-class-library)，這是 .NET 的 Lambda 執行期介面用戶端。範例 Dockerfile 使用了 Microsoft .NET 8 基礎映像。

### 先決條件
<a name="dotnet-csharp-alt-prerequisites"></a>

若要完成本節中的步驟，您必須執行下列各項：
+ [.NET SDK](https://dotnet.microsoft.com/download) – 下列步驟使用 .NET 9 基礎映像。確保您的 .NET 版本與您在 Dockerfile 中指定的基礎映像的版本相符。
+ [Docker](https://docs.docker.com/get-docker) (最低版本 25.0.0)
+ Docker [buildx 外掛程式](https://github.com/docker/buildx/blob/master/README.md)。

### 使用替代基礎映像建立和部署映像
<a name="dotnet-alt-create"></a>

1. 安裝 [Amazon.Lambda.Templates](https://github.com/aws/aws-lambda-dotnet#dotnet-cli-templates) NuGet 套件。

   ```
   dotnet new install Amazon.Lambda.Templates
   ```

1. 使用 `lambda.CustomRuntimeFunction` 範本建立 .NET 專案。此範本包含 [Amazon.Lambda.RuntimeSupport](https://github.com/aws/aws-lambda-dotnet/blob/master/Libraries/src/Amazon.Lambda.RuntimeSupport/README.md#using-amazonlambdaruntimesupport-as-a-class-library) 套件。

   ```
   dotnet new lambda.CustomRuntimeFunction --name MyFunction --region us-east-1
   ```

1. 導覽至 `MyFunction/src/MyFunction` 目錄。這是儲存專案檔案的位置。檢查下列檔案：
   + **aws-lambda-tools-defaults.json** – 您在部署 Lambda 函數時，在此檔案中指定命令列選項。
   + **Function.cs**：此程式碼含有一個類別，其中包含可將 `Amazon.Lambda.RuntimeSupport` 程式庫初始化為自舉的 `Main` 方法。`Main` 方法是函數處理過程的進入點。`Main` 方法會將函數處理常式包裝在自舉可以使用的包裝函式之中。如需詳細資訊，請參閱 GitHub 儲存庫中的 [Using Amazon.Lambda.RuntimeSupport as a class library](https://github.com/aws/aws-lambda-dotnet/blob/master/Libraries/src/Amazon.Lambda.RuntimeSupport/README.md#using-amazonlambdaruntimesupport-as-a-class-library)。
   + **MyFunction.csproj** – 一個 .NET [專案檔案](https://learn.microsoft.com/en-us/dotnet/core/project-sdk/overview#project-files)，列出了構成您的應用程式的檔案和組件。
   + **Readme.md**：此檔案包含有關範例 Lambda 函數的詳細資訊。

1. 開啓 `aws-lambda-tools-defaults.json` 檔案並「新增」下列幾行程式碼：

   ```
     "package-type": "image",
     "docker-host-build-output-dir": "./bin/Release/lambda-publish"
   ```
   + **package-type**：將部署套件定義為容器映像。
   + **docker-host-build-output-dir**：為建置過程設定輸出目錄。  
**Example aws-lambda-tools-defaults.json**  

   ```
   {
     "Information": [
       "This file provides default values for the deployment wizard inside Visual Studio and the AWS Lambda commands added to the .NET Core CLI.",
       "To learn more about the Lambda commands with the .NET Core CLI execute the following command at the command line in the project root directory.",
       "dotnet lambda help",
       "All the command line options for the Lambda command can be specified in this file."
     ],
     "profile": "",
     "region": "us-east-1",
     "configuration": "Release",
     "function-runtime": "provided.al2023",
     "function-memory-size": 256,
     "function-timeout": 30,
     "function-handler": "bootstrap",
     "msbuild-parameters": "--self-contained true",
     "package-type": "image",
     "docker-host-build-output-dir": "./bin/Release/lambda-publish"
   }
   ```

1. 在 `MyFunction/src/MyFunction` 目錄建立 Dockerfile。下列範例 Dockerfile 使用 Microsoft .NET 基礎映像，而非 [AWS  基礎映像](#csharp-image-base)。
   + 將 `FROM` 屬性設為基礎映像識別符。基礎映像和 `MyFunction.csproj` 檔案中的 `TargetFramework` 都必須使用相同的 .NET 版本。
   + 使用 `COPY` 命令將函數複製到 `/var/task` 目錄。
   + 將 `ENTRYPOINT` 設為您希望 Docker 容器在啟動時執行的模組。在這種情況下，該模組是會初始化 `Amazon.Lambda.RuntimeSupport` 程式庫的自舉。

   請注意，範例 Dockerfile 不包含 [USER 指令](https://docs.docker.com/reference/dockerfile/#user)。當您將容器映像部署到 Lambda 時，Lambda 會自動定義一個具有最低權限許可的預設 Linux 使用者。這與標準 Docker 行為不同，後者會在未提供 `USER` 指令時預設為 `root` 使用者。  
**Example Dockerfile**  

   ```
   # You can also pull these images from DockerHub amazon/aws-lambda-dotnet:8
   FROM mcr.microsoft.com/dotnet/runtime:9.0
   
   # Set the image's internal work directory
   WORKDIR /var/task
     
   # Copy function code to Lambda-defined environment variable
   COPY "bin/Release/net9.0/linux-x64"  .
     
   # Set the entrypoint to the bootstrap
   ENTRYPOINT ["/usr/bin/dotnet", "exec", "/var/task/bootstrap.dll"]
   ```

1. 安裝 Amazon.Lambda.Tools [.NET Global Tools 延伸模組](https://aws.amazon.com/blogs/developer/net-core-global-tools-for-aws/)。

   ```
   dotnet tool install -g Amazon.Lambda.Tools
   ```

   如果已安裝 Amazon.Lambda.Tools，則請確保您有最新版本。

   ```
   dotnet tool update -g Amazon.Lambda.Tools
   ```

1. 使用 Amazon.Lambda.Tools 建置 Docker 映像檔，將其推送至新的 Amazon ECR 儲存庫，然後部署 Lambda 函數。

   對於 `--function-role`，指定函數[執行角色](lambda-intro-execution-role.md)的角色名稱 (而非 Amazon Resource Name (ARN))。例如 `lambda-role`。

   ```
   dotnet lambda deploy-function MyFunction --function-role lambda-role
   ```

   如需有關 Amazon.Lambda.Tools .NET CLI 延伸模組的詳細資訊，請參閱 GitHub 上的 [.NET CLI 的AWS 延伸模組](https://github.com/aws/aws-extensions-for-dotnet-cli)儲存庫。

1. 調用函數。

   ```
   dotnet lambda invoke-function MyFunction --payload "Testing the function"
   ```

   如果一切順利，您會看到下列項目：

   ```
   Payload:
   "TESTING THE FUNCTION"
   
   Log Tail:
   START RequestId: id Version: $LATEST
   END RequestId: id
   REPORT RequestId: id  Duration: 0.99 ms       Billed Duration: 1 ms         Memory Size: 256 MB     Max Memory Used: 12 MB
   ```

1. 刪除 Lambda 函數。

   ```
   dotnet lambda delete-function MyFunction
   ```

# 將 .NET Lambda 函數程式碼編譯為原生執行時期格式
<a name="dotnet-native-aot"></a>

.NET 8 支援原生預先 (AOT) 編譯。使用原生 AOT，您可以將 Lambda 函數程式碼編譯為原生執行階段格式，這樣便不需要在執行階段編譯 .NET 程式碼。原生 AOT 編譯可縮短以 .NET 撰寫之 Lambda 函數的冷啟動時間。如需詳細資訊，請參閱 AWS 運算部落格上的[適用於 AWS Lambda 的 .NET 8 執行時期簡介](https://aws.amazon.com/blogs/compute/introducing-the-net-8-runtime-for-aws-lambda/)。

**Topics**
+ [

## Lambda 執行時間
](#dotnet-native-aot-runtime)
+ [

## 必要條件
](#dotnet-native-aot-prerequisites)
+ [

## 開始使用
](#dotnet-native-aot-getting-started)
+ [

## 序列化
](#dotnet-native-aot-serialization)
+ [

## 裁剪
](#dotnet-native-aot-trimming)
+ [

## 疑難排解
](#dotnet-native-aot-troubleshooting)

## Lambda 執行時間
<a name="dotnet-native-aot-runtime"></a>

若要使用原生 AOT 編譯部署 Lambda 函數建置，請使用受管 .NET 8 Lambda 執行時期。此執行時期支援同時使用 x86\$164 和 arm64 架構。

不使用 AOT 來部署 .NET Lambda 函數時，您的應用程式會首先編譯成中繼語言 (IL) 程式碼。在執行時期，Lambda 執行時期中的即時 (JIT) 編譯器需使用 IL 程式碼，並根據需要編譯為機器碼。透過使用原生 AOT 預先編譯的 Lambda 函數，可以在部署函數時將程式碼編譯為機器程式碼，因此在執行之前，您不需要依賴 Lambda 執行時期中的 .NET 執行時期或 SDK 來編譯程式碼。

AOT 的一個限制是，應用程式碼必須在與 .NET 8 執行時期使用的 Amazon Linux 2023 (AL2023) 作業系統相同的環境中進行編譯。.NET Lambda CLI 提供使用 AL2023 映像檔在 Docker 容器中編譯應用程式的功能。

為了避免跨架構相容性的潛在問題，強烈建議您在具有您為函數設定之相同處理器架構的環境中編譯程式碼。若要進一步了解跨架構編譯的限制，請參閱 Microsoft .NET 文件中的[跨編譯](https://learn.microsoft.com/en-us/dotnet/core/deploying/native-aot/cross-compile)。

## 必要條件
<a name="dotnet-native-aot-prerequisites"></a>

**Docker**  
若要使用原生 AOT，編譯函數程式碼時所用環境的 AL2023 作業系統必須與 .NET 8 執行時期相同。以下各節中的 .NET CLI 命令，使用 Docker 在 AL2023 環境中開發和建置 Lambda 函數。

**.NET 8 SDK**  
原生 AOT 編譯是 .NET 8 的一項功能。除了執行時期之外，您也必須在建置機器上安裝 [.NET 8 SDK](https://dotnet.microsoft.com/en-us/download/dotnet/8.0)。

**Amazon.Lambda.Tools**  
若要建立 Lambda 函數，請使用 [https://www.nuget.org/packages/Amazon.Lambda.Tools](https://www.nuget.org/packages/Amazon.Lambda.Tools) [.NET Core Global Tools 延伸模組](https://aws.amazon.com/blogs/developer/net-core-global-tools-for-aws/)。若要安裝 Amazon.Lambda.Tools，請執行下列命令：  

```
dotnet tool install -g Amazon.Lambda.Tools
```
如需有關 Amazon.Lambda.Tools .NET CLI 延伸模組的詳細資訊，請參閱 GitHub 上的[適用於 .NET CLI 的 AWS 延伸模組](https://github.com/aws/aws-extensions-for-dotnet-cli)儲存庫。

**Amazon.Lambda.Templates**  
若要產生 Lambda 函數程式碼，請使用 [https://www.nuget.org/packages/Amazon.Lambda.Templates](https://www.nuget.org/packages/Amazon.Lambda.Templates) NuGet 套件。若要安裝此範本套件，請執行下列命令：  

```
dotnet new install Amazon.Lambda.Templates
```

## 開始使用
<a name="dotnet-native-aot-getting-started"></a>

.NET Global CLI 和 AWS Serverless Application Model (AWS SAM) 都提供使用原生 AOT 建置應用程式的入門範本。若要建置您的第一個原生 AOT Lambda 函數，請按照下列指示中的步驟操作。

**初始化和部署原生 AOT 編譯的 Lambda 函數**

1. 使用原生 AOT 範本初始化新專案，然後瀏覽至包含所建立 `.cs` 和 `.csproj` 檔案的目錄。在此範例中，我們將函數命名為 `NativeAotSample`。

   ```
   dotnet new lambda.NativeAOT -n NativeAotSample
   cd ./NativeAotSample/src/NativeAotSample
   ```

   原生 AOT 範本建立的 `Function.cs` 檔案包含以下函數程式碼。

   ```
   using Amazon.Lambda.Core;
   using Amazon.Lambda.RuntimeSupport;
   using Amazon.Lambda.Serialization.SystemTextJson;
   using System.Text.Json.Serialization;
   
   namespace NativeAotSample;
   
   public class Function
   {
       /// <summary>
       /// The main entry point for the Lambda function. The main function is called once during the Lambda init phase. It
       /// initializes the .NET Lambda runtime client passing in the function handler to invoke for each Lambda event and
       /// the JSON serializer to use for converting Lambda JSON format to the .NET types.
       /// </summary>
       private static async Task Main()
       {
           Func<string, ILambdaContext, string> handler = FunctionHandler;
           await LambdaBootstrapBuilder.Create(handler, new SourceGeneratorLambdaJsonSerializer<LambdaFunctionJsonSerializerContext>())
               .Build()
               .RunAsync();
       }
   
       /// <summary>
       /// A simple function that takes a string and does a ToUpper.
       ///
       /// To use this handler to respond to an AWS event, reference the appropriate package from
       /// https://github.com/aws/aws-lambda-dotnet#events
       /// and change the string input parameter to the desired event type. When the event type
       /// is changed, the handler type registered in the main method needs to be updated and the LambdaFunctionJsonSerializerContext
       /// defined below will need the JsonSerializable updated. If the return type and event type are different then the
       /// LambdaFunctionJsonSerializerContext must have two JsonSerializable attributes, one for each type.
       ///
       // When using Native AOT extra testing with the deployed Lambda functions is required to ensure
       // the libraries used in the Lambda function work correctly with Native AOT. If a runtime
       // error occurs about missing types or methods the most likely solution will be to remove references to trim-unsafe
       // code or configure trimming options. This sample defaults to partial TrimMode because currently the AWS
       // SDK for .NET does not support trimming. This will result in a larger executable size, and still does not
       // guarantee runtime trimming errors won't be hit.
       /// </summary>
       /// <param name="input"></param>
       /// <param name="context"></param>
       /// <returns></returns>
       public static string FunctionHandler(string input, ILambdaContext context)
       {
           return input.ToUpper();
       }
   }
   
   /// <summary>
   /// This class is used to register the input event and return type for the FunctionHandler method with the System.Text.Json source generator.
   /// There must be a JsonSerializable attribute for each type used as the input and return type or a runtime error will occur
   /// from the JSON serializer unable to find the serialization information for unknown types.
   /// </summary>
   [JsonSerializable(typeof(string))]
   public partial class LambdaFunctionJsonSerializerContext : JsonSerializerContext
   {
       // By using this partial class derived from JsonSerializerContext, we can generate reflection free JSON Serializer code at compile time
       // which can deserialize our class and properties. However, we must attribute this class to tell it what types to generate serialization code for.
       // See https://docs.microsoft.com/en-us/dotnet/standard/serialization/system-text-json-source-generation
   ```

   原生 AOT 會將應用程式編譯成單一原生二進位檔。該二進位檔的進入點是 `static Main` 方法。在 `static Main` 中，系統會引導 Lambda 執行期並設定 `FunctionHandler` 方法。在執行期引導程序中，原始碼產生的序列化程式是使用 `new SourceGeneratorLambdaJsonSerializer<LambdaFunctionJsonSerializerContext>()` 加以設定

1. 若要將應用程式部署到 Lambda，請確定本機環境中的 Docker 正在執行，並執行下列命令。

   ```
   dotnet lambda deploy-function
   ```

   在背景中，.NET Global CLI 會下載 AL2023 Docker 映像檔，並在執行中的容器內編譯應用程式程式碼。編譯後的二進位檔會輸出回本機檔案系統，然後再部署至 Lambda。

1. 執行以下命令來測試函數。以您在部署精靈中為函數選擇的名稱取代 `<FUNCTION_NAME>`。

   ```
   dotnet lambda invoke-function <FUNCTION_NAME> --payload "hello world"
   ```

   CLI 的回應包括冷啟動 (初始化持續時間) 的效能詳細資訊，以及函數調用的總執行時間。

1. 若要依照上述步驟刪除您建立的 AWS 資源，請執行下列命令。以您在部署精靈中為函數選擇的名稱取代 `<FUNCTION_NAME>`。刪除您不再使用的 AWS 資源，可為 AWS 帳戶避免不必要的費用。

   ```
   dotnet lambda delete-function <FUNCTION_NAME>
   ```

## 序列化
<a name="dotnet-native-aot-serialization"></a>

若要使用原生 AOT 將函數部署至 Lambda，您的函數程式碼必須使用[原始碼產生的序列化](https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json/source-generation-modes?pivots=dotnet-8-0)。原始碼產生器不會使用執行期反射，來收集序列化存取物件屬性所需的中繼資料，而是會產生建置應用程式時編譯的 C\$1 原始碼檔案。若要正確設定原始碼產生的序列化程式，請確認函數使用的所有輸入和輸出物件及自訂類型都包含在內。例如，接收來自 API Gateway REST API 的事件並傳回自訂 `Product` 類型的 Lambda 函數，會包含定義如下的序列化程式。

```
[JsonSerializable(typeof(APIGatewayProxyRequest))]
[JsonSerializable(typeof(APIGatewayProxyResponse))]
[JsonSerializable(typeof(Product))]
public partial class CustomSerializer : JsonSerializerContext
{
}
```

## 裁剪
<a name="dotnet-native-aot-trimming"></a>

本機 AOT 會在編譯過程中裁剪應用程式程式碼，以盡可能縮小二進位檔。與舊版 .NET 相比，適用於 Lambda 的 .NET 8 可提供更好的修剪支援。支援已新增至 [Lambda 執行時期程式庫](https://github.com/aws/aws-lambda-dotnet/pull/1596)、[AWS .NET SDK](https://github.com/aws/aws-sdk-net/pulls?q=is%3Apr+trimming)、[.NET Lambda Annotations](https://github.com/aws/aws-lambda-dotnet/pull/1610)和 .NET 8 本身。

這些改進可能消除建置時間修剪警告，但 .NET 永遠不會完全安全修剪。這表示函數相依的程式庫，可能會在編譯過程中遭到部分裁剪。可以透過將 `TrimmerRootAssemblies` 定義為 `.csproj` 檔案的一部分來管理此問題，如下列範例所示。

```
<ItemGroup>
    <TrimmerRootAssembly Include="AWSSDK.Core" />
    <TrimmerRootAssembly Include="AWSXRayRecorder.Core" />
    <TrimmerRootAssembly Include="AWSXRayRecorder.Handlers.AwsSdk" />
    <TrimmerRootAssembly Include="Amazon.Lambda.APIGatewayEvents" />
    <TrimmerRootAssembly Include="bootstrap" />
    <TrimmerRootAssembly Include="Shared" />
</ItemGroup>
```

請注意，當您收到修剪警告時，將產生警告的類別新增至 `TrimmerRootAssembly` 可能無法解決問題。修剪警告表示類別正在嘗試存取一些其他類別，它們在執行時期之前無法確定。若要避免執行時期錯誤，請將此第二個類別新增至 `TrimmerRootAssembly`。

若要進一步了解如何管理修剪警告，請參閱 Microsoft .NET 文件中的[修剪警告簡介](https://learn.microsoft.com/en-us/dotnet/core/deploying/trimming/fixing-warnings)。

## 疑難排解
<a name="dotnet-native-aot-troubleshooting"></a>

**Error: Cross-OS native compilation is not supported (錯誤：不支援跨作業系統原生編譯)。**  
您的 Amazon.Lambda.Tools .NET Core 全域工具版本太舊。請更新至最新版本再重試。

**Docker: image operating system "linux" cannot be used on this platform (Docker：映像檔作業系統 "linux" 不能在此平台上使用)。**  
系統上的 Docker 設定為使用 Windows 容器。請更換至 Linux 容器以執行原生 AOT 建置環境。

如需有關常見錯誤的詳細資訊，請參閱 GitHub 上的[適用於 .NET 的 AWS NativeAOT](https://github.com/awslabs/dotnet-nativeaot-labs#common-errors) 儲存庫。

# 使用 Lambda 內容物件擷取 C\$1 函數資訊
<a name="csharp-context"></a>

當 Lambda 執行您的函數時，它會將內容物件傳遞至[處理常式](csharp-handler.md)。此物件提供的各項屬性包含了有關叫用、函式以及執行環境的資訊。

**內容屬性**
+ `FunctionName` – Lambda 函數的名稱。
+ `FunctionVersion` – 函數的[版本](configuration-versions.md)。
+ `InvokedFunctionArn` - 用於調用此函數的 Amazon Resource Name (ARN)。指出調用者是否指定版本號或別名。
+ `MemoryLimitInMB` - 分配給函數的記憶體數量。
+ `AwsRequestId` - 調用請求的識別符。
+ `LogGroupName` - 函數的日誌群組。
+ `LogStreamName` - 函數執行個體的記錄串流。
+ `RemainingTime`(`TimeSpan`) - 執行逾時前剩餘的毫秒數。
+ `Identity` - (行動應用程式) 已授權請求的 Amazon Cognito 身分的相關資訊。
+ `ClientContext` - (行動應用程式) 用戶端應用程式提供給 Lambda 的用戶端內容。
+ `Logger` 函式的 [Logger 物件](csharp-logging.md)。

基於監控目的，您可以使用 `ILambdaContext` 物件中的資訊來輸出函數調用的相關資訊。下列程式碼範例說明如何將內容資訊新增至結構化日誌記錄架構。在此範例中，函數會將 `AwsRequestId` 新增至日誌輸出。如果 Lambda 函數即將逾時，函數也會使用 `RemainingTime` 屬性取消傳輸中的任務。

```
[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))]

namespace GetProductHandler;

public class Function
{
    private readonly IDatabaseRepository _repo;
    
    public Function()
    {
        this._repo = new DatabaseRepository();
    }
    
    public async Task<APIGatewayProxyResponse> FunctionHandler(APIGatewayProxyRequest request, ILambdaContext context)
    {
        Logger.AppendKey("AwsRequestId", context.AwsRequestId);
        
        var id = request.PathParameters["id"];

        using var cts = new CancellationTokenSource();
        
        try
        {
            cts.CancelAfter(context.RemainingTime.Add(TimeSpan.FromSeconds(-1)));
            
            var databaseRecord = await this._repo.GetById(id, cts.Token);
            
            return new APIGatewayProxyResponse 
            {
                StatusCode = (int)HttpStatusCode.OK,
                Body = JsonSerializer.Serialize(databaseRecord)
            };
        }
        catch (Exception ex)
        {
            return new APIGatewayProxyResponse 
            {
                StatusCode = (int)HttpStatusCode.InternalServerError,
                Body = JsonSerializer.Serialize(new { error = ex.Message })
            };
        }
        finally
        {
            cts.Cancel();
        }
    }
}
```

# 記錄和監控 C\$1 Lambda 函數
<a name="csharp-logging"></a>

AWS Lambda 會自動監控 Lambda 函數，並將日誌項目傳送至 Amazon CloudWatch。您的 Lambda 函數隨附有 CloudWatch Logs 日誌群組，且函數的每一執行個體各有一個日誌串流。Lambda 執行期環境會將每次調用的詳細資訊和函數程式碼的其他輸出，傳送至日誌串流。如需 CloudWatch Logs 的詳細資訊，請參閱[將 Lambda 函式日誌傳送至 CloudWatch Logs](monitoring-cloudwatchlogs.md)。

**Topics**
+ [

## 建立傳回日誌的函數
](#csharp-logging-output)
+ [

## 搭配 .NET 使用 Lambda 進階日誌控制項
](#csharp-logging-advanced)
+ [

## 其他日誌工具和程式庫
](#csharp-tools-libraries)
+ [

## 使用 Powertools for AWS Lambda (.NET) 和 AWS SAM 用於結構化記錄
](#dotnet-logging-sam)
+ [

## 在 Lambda 主控台檢視日誌
](#csharp-logging-console)
+ [

## 在 CloudWatch 主控台中檢視 記錄
](#csharp-logging-cwconsole)
+ [

## 使用 AWS Command Line Interface (AWS CLI) 檢視日誌
](#csharp-logging-cli)
+ [

## 刪除日誌
](#csharp-logging-delete)

## 建立傳回日誌的函數
<a name="csharp-logging-output"></a>

若要由您的函數程式碼輸出日誌，您可以使用主控台物件中的 [ILambdaLogger](https://github.com/aws/aws-lambda-dotnet/blob/master/Libraries/src/Amazon.Lambda.Core/ILambdaLogger.cs)、[主控台類別](https://docs.microsoft.com/en-us/dotnet/api/system.console)的方法，或任何能寫入 `stdout` 或 `stderr` 的記錄程式庫。

.NET 執行期會記錄每次調用的 `START`、`END` 和 `REPORT` 行。報告明細行提供下列詳細資訊。

**REPORT 行資料欄位**
+ **RequestId** - 進行調用的唯一請求 ID。
+ **持續時間** - 函數的處理常式方法處理事件所花費的時間量。
+ **計費持續時間** - 調用的計費時間量。
+ **記憶體大小** - 分配給函數的記憶體數量。
+ **使用的記憶體上限** - 函數所使用的記憶體數量。當調用共用執行環境時，Lambda 會報告所有調用使用的記憶體上限。此行為可能會導致報告值高於預期值。
+ **初始化持續時間** - 對於第一個提供的請求，這是執行期載入函數並在處理常式方法之外執行程式碼所花費的時間量。
+ **XRAY TraceId** - 對於追蹤的請求，這是 [AWS X-Ray 追蹤 ID](services-xray.md)。
+ **SegmentId** - 對於追蹤的請求，這是 X-Ray 區段 ID。
+ **已取樣** - 對於追蹤的請求，這是取樣結果。

## 搭配 .NET 使用 Lambda 進階日誌控制項
<a name="csharp-logging-advanced"></a>

為了讓您更妥善地控制擷取、處理和使用函數日誌的方式，您可以針對支援的 .NET 執行時期設定下列記錄選項：
+ **日誌格式** - 在純文字和結構化 JSON 格式之間為您的日誌進行選擇
+ **日誌層級** - 對於 JSON 格式的日誌，請選擇 Lambda 傳送到 CloudWatch 的日誌之詳細等級，例如 ERROR、DEBUG 或 INFO
+ **日誌群組** - 選擇您的函數將日誌傳送到的 CloudWatch 日誌群組

如需這些日誌選項的詳細資訊，以及如何設定函數以使用這些選項的說明，請參閱 [設定 Lambda 函數的進階日誌記錄控制項](monitoring-logs.md#monitoring-cloudwatchlogs-advanced)。

若要使用日誌格式和日誌層級選項與 .NET Lambda 函數搭配使用，請參閱以下各章節中的指引。

### 搭配 .NET 使用結構化 JSON 日誌格式
<a name="csharp-logging-advanced-JSON"></a>

如果您為函數的日誌格式選取 JSON，Lambda 會以結構化 JSON 形式使用 [ILambdaLogger](https://github.com/aws/aws-lambda-dotnet/blob/master/Libraries/src/Amazon.Lambda.Core/ILambdaLogger.cs) 來傳送日誌輸出。每個 JSON 日誌物件都包含至少五個鍵值對，其中包含下列索引鍵：
+ `"timestamp"` - 產生日誌訊息的時間
+ `"level"` - 指派給訊息的日誌層級
+ `"requestId"` - 進行調用的唯一請求 ID。
+ `"traceId"` - `_X_AMZN_TRACE_ID` 環境變數
+ `"message"` - 日誌訊息的內容

`ILambdaLogger` 執行個體可以新增其他鍵值對，例如記錄例外狀況時。您也可以提供自己的其他參數，如 [客戶提供的日誌參數](#csharp-logging-advanced-JSON-user-supplied) 章節中所述。

**注意**  
如果程式碼已使用另一個日誌程式庫來產生 JSON 格式的日誌，請確定函數的日誌格式設定為純文字。將日誌格式設定為 JSON 將導致日誌輸出進行雙重編碼。

下列記錄命令範例示範如何使用 `INFO` 層級來撰寫日誌訊息。

**Example .NET 日誌程式碼**  

```
context.Logger.LogInformation("Fetching cart from database");
```

也可以使用一般日誌方法，將日誌層級作為引數，如下列範例所示。

```
context.Logger.Log(LogLevel.Information, "Fetching cart from database");
```

會在 CloudWatch Logs 中擷取這些範例程式碼片段所輸出的日誌，如下所示：

**Example JSON 日誌記錄**  

```
{
    "timestamp": "2025-09-07T01:30:06.977Z",
    "level": "Information",
    "requestId": "8f711428-7e55-46f9-ae88-2a65d4f85fc5",
    "traceId": "1-6408af34-50f56f5b5677a7d763973804",
    "message": "Fetching cart from database"
}
```

**注意**  
如果將函數的日誌格式設定為使用純文字而非 JSON，則訊息中擷取的日誌層級會遵循使用四字元標籤的 Microsoft 慣例。例如，`Debug` 的日誌層級在訊息中表示為 `dbug`。  
將函數設定為使用 JSON 格式的日誌時，日誌中擷取的日誌層級會使用完整標籤，如範例 JSON 日誌記錄所示。

如果您沒有為日誌輸出指派層級，Lambda 會自動為其指派層級 INFO。

#### 在 JSON 中記錄例外狀況
<a name="csharp-logging-advanced-JSON-exceptions"></a>

搭配使用結構化 JSON 日誌與 `ILambdaLogger` 時，您可以在程式碼中記錄例外狀況，如下列範例所示。

**Example 例外狀況日誌的使用情況**  

```
try
{
    connection.ExecuteQuery(query);
}
catch(Exception e)
{
    context.Logger.LogWarning(e, "Error executing query");
}
```

此程式碼輸出的日誌格式會顯示在下列範例 JSON 中。請注意，使用 `LogWarning` 呼叫中提供的訊息引數來填充 JSON 中的 `message` 屬性，而 `errorMessage` 屬性來自例外狀況本身的 `Message` 屬性。

**Example JSON 日誌記錄**  

```
{
    "timestamp": "2025-09-07T01:30:06.977Z",
    "level": "Warning",
    "requestId": "8f711428-7e55-46f9-ae88-2a65d4f85fc5",
    "traceId": "1-6408af34-50f56f5b5677a7d763973804",
    "message": "Error executing query",
    "errorType": "System.Data.SqlClient.SqlException",
    "errorMessage": "Connection closed",
    "stackTrace": ["<call exception.StackTrace>"]
}
```

如果函數的日誌格式設定為 JSON，則當您的程式碼擲出未攔截的例外狀況時，Lambda 也會輸出 JSON 格式的日誌訊息。下列程式碼片段和日誌訊息範例顯示如何記錄未攔截的例外狀況。

**Example 例外狀況代碼**  

```
throw new ApplicationException("Invalid data");
```

**Example JSON 日誌記錄**  

```
{
    "timestamp": "2025-09-07T01:30:06.977Z",
    "level": "Error",
    "requestId": "8f711428-7e55-46f9-ae88-2a65d4f85fc5",
    "traceId": "1-6408af34-50f56f5b5677a7d763973804",
    "message": "Invalid data",
    "errorType": "System.ApplicationException",
    "errorMessage": "Invalid data",
    "stackTrace": ["<call exception.StackTrace>"]
}
```

#### 客戶提供的日誌參數
<a name="csharp-logging-advanced-JSON-user-supplied"></a>

使用 JSON 格式的日誌訊息，可以提供額外的日誌參數，並將這些參數包含在日誌 `message` 中。下列程式碼片段範例顯示一個命令，它可新增兩個使用者提供的參數，分別標記為 `retryAttempt` 和 `uri`。在此範例中，這些參數的值來自傳遞至日誌命令的 `retryAttempt` 和 `uriDestination` 引數。

**Example 具有其他參數的 JSON 日誌命令**  

```
context.Logger.LogInformation("Starting retry {retryAttempt} to make GET request to {uri}", retryAttempt, uriDestination);
```

此命令輸出的日誌訊息會顯示在下列範例 JSON 中。

**Example JSON 日誌記錄**  

```
{
    "timestamp": "2025-09-07T01:30:06.977Z",
    "level": "Information",
    "requestId": "8f711428-7e55-46f9-ae88-2a65d4f85fc5",
    "traceId": "1-6408af34-50f56f5b5677a7d763973804",
    "message": "Starting retry 1 to make GET request to http://example.com/",
    "retryAttempt": 1,
    "uri": "http://example.com/"
}
```

**提示**  
在指定其他參數時，也可以使用位置屬性而非名稱。例如，上一個範例中的日誌命令也可以編寫如下：  

```
context.Logger.LogInformation("Starting retry {0} to make GET request to {1}", retryAttempt, uriDestination);
```

請注意，當您提供額外的日誌參數時，Lambda 會將它們擷取為 JSON 日誌記錄中的頂層屬性。此方法與一些熱門的 .NET 日誌程式庫 (例如 `Serilog`) 不同，它會擷取個別子物件中的其他參數。

如果您為其他參數提供的引數是複雜物件，根據預設，Lambda 會使用 `ToString()` 方法提供值。若要指出引數應該是 JSON 序列化，請使用 `@` 字首，如下列程式碼片段所示。在此範例中，`User` 是具有 `FirstName` 和 `LastName` 屬性的物件。

**Example 具有 JSON 序列化物件的 JSON 日誌命令**  

```
context.Logger.LogInformation("User {@user} logged in", User);
```

此命令輸出的日誌訊息會顯示在下列範例 JSON 中。

**Example JSON 日誌記錄**  

```
{
    "timestamp": "2025-09-07T01:30:06.977Z",
    "level": "Information",
    "requestId": "8f711428-7e55-46f9-ae88-2a65d4f85fc5",
    "traceId": "1-6408af34-50f56f5b5677a7d763973804",
    "message": "User {@user} logged in",
    "user": 
    {
        "FirstName": "John",
        "LastName": "Doe"
    }
}
```

如果其他參數的引數是陣列或實作 `IList` 或 `IDictionary`，則 Lambda 會將引數新增至 JSON 日誌訊息作為陣列，如下列範例 JSON 日誌記錄所示。在此範例中，`{users}` 會採用 `IList` 引數，其中包含與先前範例格式相同的 `User` 屬性的執行個體。Lambda 會將此 `IList` 轉換為陣列，使用 `ToString` 方法建立每個值。

**Example 具有 `IList` 引數的 JSON 日誌記錄**  

```
{
    "timestamp": "2025-09-07T01:30:06.977Z",
    "level": "Information",
    "requestId": "8f711428-7e55-46f9-ae88-2a65d4f85fc5",
    "traceId": "1-6408af34-50f56f5b5677a7d763973804",
    "message": "{users} have joined the group",
    "users": 
    [
        "Rosalez, Alejandro",
        "Stiles, John"       
    ] 
}
```

也可以在日誌命令中使用 `@` 字首，對清單進行 JSON 序列化。在下列範例 JSON 日誌記錄中，`users` 屬性為 JSON 序列化。

**Example 具有 JSON 序列化 `IList` 引數的 JSON 日誌記錄**  

```
{
    "timestamp": "2025-09-07T01:30:06.977Z",
    "level": "Information",
    "requestId": "8f711428-7e55-46f9-ae88-2a65d4f85fc5",
    "traceId": "1-6408af34-50f56f5b5677a7d763973804",
    "message": "{@users} have joined the group",
    "users": 
    [
        {
            "FirstName": "Alejandro",
            "LastName": "Rosalez"
        },
        {
            "FirstName": "John",
            "LastName": "Stiles"
        }        
    ] 
}
```

### 搭配 .NET 使用日誌層級篩選
<a name="csharp-logging-advanced-levels"></a>

透過設定日誌層級篩選，您可以選擇只傳送特定詳細資訊層級或更低層級的日誌至 CloudWatch Logs。若要瞭解如何設定函數的日誌層級篩選，請參閱 [日誌層級篩選](monitoring-cloudwatchlogs-log-level.md)。

若要 AWS Lambda 讓 依日誌層級篩選日誌訊息，您可以使用 JSON 格式的日誌，或使用 .NET `Console`方法來輸出日誌訊息。若要建立 JSON 格式日誌，[請將函數的日誌類型設定為 JSON](monitoring-cloudwatchlogs-logformat.md#monitoring-cloudwatchlogs-set-format)，並使用 `ILambdaLogger` 執行個體。

使用 JSON 格式日誌，Lambda 會使用 [搭配 .NET 使用結構化 JSON 日誌格式](#csharp-logging-advanced-JSON) 中所述 JSON 物件中的「層級」索引鍵值組篩選您的日誌輸出。

如果使用 .NET `Console` 方法，將訊息寫入 CloudWatch Logs，Lambda 會將日誌層級套用至您的訊息，如下所示：
+ **Console.WriteLine 方法** - Lambda 會套用 `INFO` 的日誌層級
+ **Console.Error 方法** - Lambda 會套用 `ERROR` 的日誌層級

將函數設定為使用日誌層級篩選時，您必須從下列選項中選取要 Lambda 傳送至 CloudWatch Logs 的日誌層級。請注意 Lambda 使用的日誌層級與 .NET `ILambdaLogger` 所使用的標準 Microsoft 層級的映射。


| Lambda 日誌層級 | 同等 Microsoft 層級 | 標準用量 | 
| --- | --- | --- | 
| TRACE (大多數詳細資訊) | 追蹤 | 用於追蹤程式碼執行路徑的最精細資訊 | 
| DEBUG | 偵錯 | 系統偵錯的詳細資訊 | 
| INFO | 資訊 | 記錄函數正常操作的訊息 | 
| WARN | 警告 | 有關可能導致未解決意外行為的潛在錯誤的消息 | 
| ERROR | 錯誤 | 有關阻止程式碼按預期執行的問題的訊息 | 
| FATAL (最少詳細資訊) | 嚴重 | 有關導致應用程式停止運作的嚴重錯誤訊息 | 

Lambda 會將選取的詳細資訊層級和更低層級的日誌傳送至 CloudWatch。例如，如果您設定 WARN 的日誌層級，Lambda 會傳送相對應於 WARN、ERROR 和 FATAL 層級的日誌檔。

## 其他日誌工具和程式庫
<a name="csharp-tools-libraries"></a>

[Powertools for AWS Lambda (.NET)](https://docs.aws.amazon.com/powertools/dotnet/) 是一種開發人員工具組，可實作無伺服器最佳實務並提高開發人員速度。[記錄公用程式](https://docs.aws.amazon.com/powertools/dotnet/core/logging/)提供 Lambda 優化記錄器，其中包含有關所有函數之函數內容的其他資訊，輸出結構為 JSON。使用此公用程式執行下列操作：
+ 從 Lambda 內容、冷啟動和 JSON 形式的結構記錄輸出中擷取關鍵欄位
+ 在收到指示時記錄 Lambda 調用事件 (預設為停用)
+ 透過日誌採樣僅列印調用百分比的所有日誌 (預設為停用)
+ 在任何時間點將其他金鑰附加至結構化日誌
+ 使用自訂日誌格式化程式 (自帶格式化程式)，以與組織的日誌記錄 RFC 相容的結構輸出日誌。

## 使用 Powertools for AWS Lambda (.NET) 和 AWS SAM 用於結構化記錄
<a name="dotnet-logging-sam"></a>

請依照下列步驟，使用整合式 [Powertools for AWS Lambda () 下載、建置和部署範例 Hello World C\$1 應用程式。NET)](https://docs.powertools.aws.dev/lambda-dotnet) 模組使用 AWS SAM。此應用程式實作了基本 API 後端，並使用 Powertools 發送日誌、指標和追蹤。其包含 Amazon API Gateway 端點和 Lambda 函數。當您將 GET 請求傳送至 API Gateway 端點時，Lambda 函數會調用、使用內嵌指標格式將日誌和指標傳送至 CloudWatch，並將追蹤傳送至 AWS X-Ray。該函數會傳回 `hello world` 訊息。

**先決條件**

若要完成本節中的步驟，您必須執行下列各項：
+ .NET 8
+ [AWS CLI 第 2 版](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html)
+ [AWS SAM CLI 1.75 版或更新版本。](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html)如果您有較舊版本的 AWS SAM CLI，請參閱[升級 AWS SAM CLI](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/manage-sam-cli-versions.html#manage-sam-cli-versions-upgrade)。

**部署範例 AWS SAM 應用程式**

1. 使用 Hello World TypeScript 範本來初始化應用程式。

   ```
   sam init --app-template hello-world-powertools-dotnet --name sam-app --package-type Zip --runtime dotnet6 --no-tracing
   ```

1. 建置應用程式。

   ```
   cd sam-app && sam build
   ```

1. 部署應用程式。

   ```
   sam deploy --guided
   ```

1. 依照螢幕上的提示操作。若要接受互動體驗中提供的預設選項，請按下 `Enter`。
**注意**  
對於 **HelloWorldFunction may not have authorization defined, Is this okay?**，確保輸入 `y`。

1. 取得已部署應用程式的 URL：

   ```
   aws cloudformation describe-stacks --stack-name sam-app --query 'Stacks[0].Outputs[?OutputKey==`HelloWorldApi`].OutputValue' --output text
   ```

1. 調用 API 端點：

   ```
   curl -X GET <URL_FROM_PREVIOUS_STEP>
   ```

   成功的話，您將會看到以下回應：

   ```
   {"message":"hello world"}
   ```

1. 若要獲取該函數的日誌，請執行 [sam 日誌](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-cli-command-reference-sam-logs.html)。如需詳細資訊，請參閱《AWS Serverless Application Model 開發人員指南》** 中的 [使用日誌](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-logging.html)。

   ```
   sam logs --stack-name sam-app
   ```

   日誌輸出如下：

   ```
   2025/02/20/[$LATEST]4eaf8445ba7a4a93b999cb17fbfbecd8 2025-09-20T14:15:27.988000 INIT_START Runtime Version: dotnet:6.v13        Runtime Version ARN: arn:aws:lambda:ap-southeast-2::runtime:699f346a05dae24c58c45790bc4089f252bf17dae3997e79b17d939a288aa1ec
   2025/02/20/[$LATEST]4eaf8445ba7a4a93b999cb17fbfbecd8 2025-09-20T14:15:28.229000 START RequestId: bed25b38-d012-42e7-ba28-f272535fb80e Version: $LATEST
   2025/02/20/[$LATEST]4eaf8445ba7a4a93b999cb17fbfbecd8 2025-09-20T14:15:29.259000 2025-09-20T14:15:29.201Z        bed25b38-d012-42e7-ba28-f272535fb80e    info   {"_aws":{"Timestamp":1676902528962,"CloudWatchMetrics":[{"Namespace":"sam-app-logging","Metrics":[{"Name":"ColdStart","Unit":"Count"}],"Dimensions":[["FunctionName"],["Service"]]}]},"FunctionName":"sam-app-HelloWorldFunction-haKIoVeose2p","Service":"PowertoolsHelloWorld","ColdStart":1}
   2025/02/20/[$LATEST]4eaf8445ba7a4a93b999cb17fbfbecd8 2025-09-20T14:15:30.479000 2025-09-20T14:15:30.479Z        bed25b38-d012-42e7-ba28-f272535fb80e    info   {"ColdStart":true,"XrayTraceId":"1-63f3807f-5dbcb9910c96f50742707542","CorrelationId":"d3d4de7f-4ccc-411a-a549-4d67b2fdc015","FunctionName":"sam-app-HelloWorldFunction-haKIoVeose2p","FunctionVersion":"$LATEST","FunctionMemorySize":256,"FunctionArn":"arn:aws:lambda:ap-southeast-2:123456789012:function:sam-app-HelloWorldFunction-haKIoVeose2p","FunctionRequestId":"bed25b38-d012-42e7-ba28-f272535fb80e","Timestamp":"2025-09-20T14:15:30.4602970Z","Level":"Information","Service":"PowertoolsHelloWorld","Name":"AWS.Lambda.Powertools.Logging.Logger","Message":"Hello world API - HTTP 200"}
   2025/02/20/[$LATEST]4eaf8445ba7a4a93b999cb17fbfbecd8 2025-09-20T14:15:30.599000 2025-09-20T14:15:30.599Z        bed25b38-d012-42e7-ba28-f272535fb80e    info   {"_aws":{"Timestamp":1676902528922,"CloudWatchMetrics":[{"Namespace":"sam-app-logging","Metrics":[{"Name":"ApiRequestCount","Unit":"Count"}],"Dimensions":[["Service"]]}]},"Service":"PowertoolsHelloWorld","ApiRequestCount":1}
   2025/02/20/[$LATEST]4eaf8445ba7a4a93b999cb17fbfbecd8 2025-09-20T14:15:30.680000 END RequestId: bed25b38-d012-42e7-ba28-f272535fb80e
   2025/02/20/[$LATEST]4eaf8445ba7a4a93b999cb17fbfbecd8 2025-09-20T14:15:30.680000 REPORT RequestId: bed25b38-d012-42e7-ba28-f272535fb80e  Duration: 2450.99 ms   Billed Duration: 2692 ms Memory Size: 256 MB     Max Memory Used: 74 MB  Init Duration: 240.05 ms
   XRAY TraceId: 1-63f3807f-5dbcb9910c96f50742707542       SegmentId: 16b362cd5f52cba0
   ```

1. 這是可透過網際網路存取的公有 API 端點。建議您在測試後刪除端點。

   ```
   sam delete
   ```

### 管理日誌保留
<a name="csharp-log-retention"></a>

當您刪除函數時，不會自動刪除日誌群組。若要避免無限期地儲存日誌，請刪除日誌群組，或設定保留期間，CloudWatch 會在該時間之後自動刪除日誌。若要設定日誌保留，請將下列項目新增至您的 AWS SAM 範本：

```
Resources:
  HelloWorldFunction:
    Type: AWS::Serverless::Function
    Properties:
      # Omitting other properties

  LogGroup:
    Type: AWS::Logs::LogGroup
    Properties:
      LogGroupName: !Sub "/aws/lambda/${HelloWorldFunction}"
      RetentionInDays: 7
```

## 在 Lambda 主控台檢視日誌
<a name="csharp-logging-console"></a>

您可以在調用 Lambda 函數之後，使用 Lambda 主控台來檢視日誌輸出。

如果可以從內嵌**程式碼**編輯器測試您的程式碼，您會在**執行結果**中找到日誌。使用主控台測試功能以調用函數時，您會在**詳細資訊**區段找到**日誌輸出**。

## 在 CloudWatch 主控台中檢視 記錄
<a name="csharp-logging-cwconsole"></a>

您可以使用 Amazon CloudWatch 主控台來檢視所有 Lambda 函數調用的日誌。

**若要在 CloudWatch 主控台上檢視日誌**

1. 在 CloudWatch 主控台上開啟[日誌群組頁面](https://console.aws.amazon.com/cloudwatch/home?#logs:)。

1. 選擇您的函數的日誌群組 (**/aws/lambda/*your-function-name***)。

1. 選擇日誌串流

每個日誌串流都會對應至[函式的執行個體](lambda-runtime-environment.md)。當您更新 Lambda 函數，以及建立其他執行個體以處理並行調用時，就會顯示日誌串流。若要尋找特定調用的日誌，建議您使用 檢測函數 AWS X-Ray。X-Ray 會在追蹤內記錄有關請求和日誌串流的詳細資訊。

## 使用 AWS Command Line Interface (AWS CLI) 檢視日誌
<a name="csharp-logging-cli"></a>

是一種 AWS CLI 開放原始碼工具，可讓您使用命令列 Shell 中的 命令與 AWS 服務互動。若要完成本節中的步驟，您必須擁有 [AWS CLI 版本 2](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html)。

您可以透過 [AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-welcome.html)，使用 `--log-type` 命令選項來擷取要調用的日誌。其回應將包含 `LogResult` 欄位，內含該次調用的 base64 編碼日誌 (最大達 4 KB)。

**Example 擷取日誌 ID**  
下列範例顯示如何從名稱為 `my-function` 的函數的 `LogResult` 欄位來擷取*日誌 ID*。  

```
aws lambda invoke --function-name my-function out --log-type Tail
```
您應該會看到下列輸出：  

```
{
    "StatusCode": 200,
    "LogResult": "U1RBUlQgUmVxdWVzdElkOiA4N2QwNDRiOC1mMTU0LTExZTgtOGNkYS0yOTc0YzVlNGZiMjEgVmVyc2lvb...",
    "ExecutedVersion": "$LATEST"
}
```

**Example 解碼日誌**  
在相同的命令提示中，使用 `base64` 公用程式來解碼日誌。下列範例顯示如何擷取 `my-function` 的 base64 編碼日誌。  

```
aws lambda invoke --function-name my-function out --log-type Tail \
--query 'LogResult' --output text --cli-binary-format raw-in-base64-out | base64 --decode
```
如果您使用的是第 2 AWS CLI 版，則需要 **cli-binary-format**選項。若要讓此成為預設的設定，請執行 `aws configure set cli-binary-format raw-in-base64-out`。若要取得更多資訊，請參閱*《AWS Command Line Interface 使用者指南第 2 版》*中 [AWS CLI 支援的全域命令列選項](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-options.html#cli-configure-options-list)。  
您應該會看到下列輸出：  

```
START RequestId: 57f231fb-1730-4395-85cb-4f71bd2b87b8 Version: $LATEST
"AWS_SESSION_TOKEN": "AgoJb3JpZ2luX2VjELj...", "_X_AMZN_TRACE_ID": "Root=1-5d02e5ca-f5792818b6fe8368e5b51d50;Parent=191db58857df8395;Sampled=0"",ask/lib:/opt/lib",
END RequestId: 57f231fb-1730-4395-85cb-4f71bd2b87b8
REPORT RequestId: 57f231fb-1730-4395-85cb-4f71bd2b87b8  Duration: 79.67 ms      Billed Duration: 80 ms         Memory Size: 128 MB     Max Memory Used: 73 MB
```
該 `base64` 公用程式可在 Linux、macOS 和 [Ubuntu on Windows](https://docs.microsoft.com/en-us/windows/wsl/install-win10) 上使用。macOS 使用者可能需要使用 `base64 -D`。

**Example get-logs.sh 指令碼**  
在相同的命令提示中，使用下列指令碼下載最後五個日誌事件。該指令碼使用 `sed` 以從輸出檔案移除引述，並休眠 15 秒以使日誌可供使用。輸出包括來自 Lambda 的回應以及來自 `get-log-events` 命令的輸出。  
複製下列程式碼範例的內容，並將您的 Lambda 專案目錄儲存為 `get-logs.sh`。  
如果您使用的是第 2 AWS CLI 版，則需要 **cli-binary-format**選項。若要讓此成為預設的設定，請執行 `aws configure set cli-binary-format raw-in-base64-out`。若要取得更多資訊，請參閱*《AWS Command Line Interface 使用者指南第 2 版》*中 [AWS CLI 支援的全域命令列選項](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-options.html#cli-configure-options-list)。  

```
#!/bin/bash
aws lambda invoke --function-name my-function --cli-binary-format raw-in-base64-out --payload '{"key": "value"}' out
sed -i'' -e 's/"//g' out
sleep 15
aws logs get-log-events --log-group-name /aws/lambda/my-function --log-stream-name stream1 --limit 5
```

**Example macOS 和 Linux (僅限)**  
在相同的命令提示中，macOS 和 Linux 使用者可能需要執行下列命令，以確保指令碼可執行。  

```
chmod -R 755 get-logs.sh
```

**Example 擷取最後五個記錄事件**  
在相同的命令提示中，執行下列指令碼以取得最後五個日誌事件。  

```
./get-logs.sh
```
您應該會看到下列輸出：  

```
{
    "StatusCode": 200,
    "ExecutedVersion": "$LATEST"
}
{
    "events": [
        {
            "timestamp": 1559763003171,
            "message": "START RequestId: 4ce9340a-b765-490f-ad8a-02ab3415e2bf Version: $LATEST\n",
            "ingestionTime": 1559763003309
        },
        {
            "timestamp": 1559763003173,
            "message": "2019-06-05T19:30:03.173Z\t4ce9340a-b765-490f-ad8a-02ab3415e2bf\tINFO\tENVIRONMENT VARIABLES\r{\r  \"AWS_LAMBDA_FUNCTION_VERSION\": \"$LATEST\",\r ...",
            "ingestionTime": 1559763018353
        },
        {
            "timestamp": 1559763003173,
            "message": "2019-06-05T19:30:03.173Z\t4ce9340a-b765-490f-ad8a-02ab3415e2bf\tINFO\tEVENT\r{\r  \"key\": \"value\"\r}\n",
            "ingestionTime": 1559763018353
        },
        {
            "timestamp": 1559763003218,
            "message": "END RequestId: 4ce9340a-b765-490f-ad8a-02ab3415e2bf\n",
            "ingestionTime": 1559763018353
        },
        {
            "timestamp": 1559763003218,
            "message": "REPORT RequestId: 4ce9340a-b765-490f-ad8a-02ab3415e2bf\tDuration: 26.73 ms\tBilled Duration: 27 ms \tMemory Size: 128 MB\tMax Memory Used: 75 MB\t\n",
            "ingestionTime": 1559763018353
        }
    ],
    "nextForwardToken": "f/34783877304859518393868359594929986069206639495374241795",
    "nextBackwardToken": "b/34783877303811383369537420289090800615709599058929582080"
}
```

## 刪除日誌
<a name="csharp-logging-delete"></a>

當您刪除函數時，不會自動刪除日誌群組。若要避免無限期地儲存日誌，請刪除日誌群組，或[設定保留期間](https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/Working-with-log-groups-and-streams.html#SettingLogRetention)，系統會在該時間之後自動刪除日誌。

# 在 中檢測 C\$1 程式碼 AWS Lambda
<a name="csharp-tracing"></a>

Lambda 與 整合 AWS X-Ray ，以協助您追蹤、偵錯和最佳化 Lambda 應用程式。您可以使用 X-Ray 來追蹤請求，因為它會周遊您應用程式中的資源，其中可能包含 Lambda 函數和其他 AWS 服務。

若要將追蹤資料傳送至 X-Ray，您可以使用以下三個 SDK 庫之一：
+ [AWS Distro for OpenTelemetry (ADOT)](https://aws.amazon.com/otel) – OpenTelemetry (OTel) SDK 的安全、生產就緒、 AWS支援的分發。
+ [適用於 .NET 的 AWS X-Ray SDK](https://docs.aws.amazon.com/xray/latest/devguide/xray-sdk-dotnet.html) – 用於生成追蹤資料並將其傳送至 X-Ray 的 SDK。
+ [Powertools for AWS Lambda (.NET)](https://docs.aws.amazon.com/powertools/dotnet/) – 開發人員工具組，用於實作無伺服器最佳實務並提高開發人員速度。

每個 SDK 均提供將遙測資料傳送至 X-Ray 服務的方法。然後，您可以使用 X-Ray 來檢視、篩選應用程式的效能指標並獲得洞察，從而識別問題和進行最佳化的機會。

**重要**  
X-Ray 和 Powertools AWS Lambda SDKs是 提供的緊密整合檢測解決方案的一部分 AWS。ADOT Lambda Layers 是用於追蹤檢測之業界通用標準的一部分，這類檢測一般會收集更多資料，但可能不適用於所有使用案例。您可以使用任一解決方案在 X-Ray 中實作端對端追蹤。若要深入了解如何在兩者之間做選擇，請參閱[在 AWS Distro for OpenTelemetry 和 X-Ray SDK 之間進行選擇](https://docs.aws.amazon.com/xray/latest/devguide/xray-instrumenting-your-app.html#xray-instrumenting-choosing)。

**Topics**
+ [

## 使用 Powertools for AWS Lambda (.NET) 和 AWS SAM 用於追蹤
](#dotnet-tracing-sam)
+ [

## 使用 X-Ray SDK 來檢測 .NET 函數
](#dotnet-xray-sdk)
+ [

## 透過 Lambda 主控台來啟用追蹤
](#dotnet-tracing-console)
+ [

## 透過 Lambda API 啟用追蹤
](#dotnet-tracing-api)
+ [

## 使用 啟用追蹤 CloudFormation
](#dotnet-tracing-cloudformation)
+ [

## 解讀 X-Ray 追蹤
](#dotnet-tracing-interpretation)

## 使用 Powertools for AWS Lambda (.NET) 和 AWS SAM 用於追蹤
<a name="dotnet-tracing-sam"></a>

請依照下列步驟，使用整合式 [Powertools for AWS Lambda () 下載、建置和部署範例 Hello World C\$1 應用程式。NET)](https://docs.powertools.aws.dev/lambda-dotnet) 模組使用 AWS SAM。此應用程式實作了基本 API 後端，並使用 Powertools 發送日誌、指標和追蹤。其包含 Amazon API Gateway 端點和 Lambda 函數。當您將 GET 請求傳送至 API Gateway 端點時，Lambda 函數會調用、使用內嵌指標格式將日誌和指標傳送至 CloudWatch，並將追蹤傳送至 AWS X-Ray。函數會傳回 hello world 訊息。

**先決條件**

若要完成本節中的步驟，您必須執行下列各項：
+ .NET 8
+ [AWS CLI 第 2 版](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html)
+ [AWS SAM CLI 1.75 版或更新版本。](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html)如果您有較舊版本的 AWS SAM CLI，請參閱[升級 AWS SAM CLI](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/manage-sam-cli-versions.html#manage-sam-cli-versions-upgrade)。

**部署範例 AWS SAM 應用程式**

1. 使用 Hello World TypeScript 範本來初始化應用程式。

   ```
   sam init --app-template hello-world-powertools-dotnet --name sam-app --package-type Zip --runtime dotnet6 --no-tracing
   ```

1. 建置應用程式。

   ```
   cd sam-app && sam build
   ```

1. 部署應用程式。

   ```
   sam deploy --guided
   ```

1. 依照螢幕上的提示操作。若要接受互動體驗中提供的預設選項，請按下 `Enter`。
**注意**  
對於 **HelloWorldFunction may not have authorization defined, Is this okay?**，確保輸入 `y`。

1. 取得已部署應用程式的 URL：

   ```
   aws cloudformation describe-stacks --stack-name sam-app --query 'Stacks[0].Outputs[?OutputKey==`HelloWorldApi`].OutputValue' --output text
   ```

1. 調用 API 端點：

   ```
   curl <URL_FROM_PREVIOUS_STEP>
   ```

   成功的話，您將會看到以下回應：

   ```
   {"message":"hello world"}
   ```

1. 若要取得函數的追蹤，請執行 [sam 追蹤](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-cli-command-reference-sam-traces.html)。

   ```
   sam traces
   ```

   追蹤輸出如下：

   ```
   New XRay Service Graph
     Start time: 2023-02-20 23:05:16+08:00
     End time: 2023-02-20 23:05:16+08:00
     Reference Id: 0 - AWS::Lambda - sam-app-HelloWorldFunction-pNjujb7mEoew - Edges: [1]
      Summary_statistics:
        - total requests: 1
        - ok count(2XX): 1
        - error count(4XX): 0
        - fault count(5XX): 0
        - total response time: 2.814
     Reference Id: 1 - AWS::Lambda::Function - sam-app-HelloWorldFunction-pNjujb7mEoew - Edges: []
      Summary_statistics:
        - total requests: 1
        - ok count(2XX): 1
        - error count(4XX): 0
        - fault count(5XX): 0
        - total response time: 2.429
     Reference Id: 2 - (Root) AWS::ApiGateway::Stage - sam-app/Prod - Edges: [0]
      Summary_statistics:
        - total requests: 1
        - ok count(2XX): 1
        - error count(4XX): 0
        - fault count(5XX): 0
        - total response time: 2.839
     Reference Id: 3 - client - sam-app/Prod - Edges: [2]
      Summary_statistics:
        - total requests: 0
        - ok count(2XX): 0
        - error count(4XX): 0
        - fault count(5XX): 0
        - total response time: 0
   
   XRay Event [revision 3] at (2023-02-20T23:05:16.521000) with id (1-63f38c2c-270200bf1d292a442c8e8a00) and duration (2.877s)
    - 2.839s - sam-app/Prod [HTTP: 200]
      - 2.836s - Lambda [HTTP: 200]
    - 2.814s - sam-app-HelloWorldFunction-pNjujb7mEoew [HTTP: 200]
    - 2.429s - sam-app-HelloWorldFunction-pNjujb7mEoew
      - 0.230s - Initialization
      - 2.389s - Invocation
        - 0.600s - ## FunctionHandler
          - 0.517s - Get Calling IP
      - 0.039s - Overhead
   ```

1. 這是可透過網際網路存取的公有 API 端點。建議您在測試後刪除端點。

   ```
   sam delete
   ```

X-Ray 無法追蹤應用程式的所有請求。X-Ray 會套用取樣演算法以確保追蹤的效率，同時仍提供所有請求的代表範本。取樣率為每秒 1 次請求和 5% 的額外請求。不能針對函數設定 X-Ray 取樣率。

## 使用 X-Ray SDK 來檢測 .NET 函數
<a name="dotnet-xray-sdk"></a>

您可以測試函數代碼以記錄中繼資料並追蹤下游呼叫。若要記錄函數對其他資源和服務所發出呼叫的詳細資訊，請使用 適用於 .NET 的 AWS X-Ray SDK。要取得開發套件，請將 `AWSXRayRecorder` 套件新增到您的專案檔案中。

```
<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
    <GenerateRuntimeConfigurationFiles>true</GenerateRuntimeConfigurationFiles>
    <AWSProjectType>Lambda</AWSProjectType>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="Amazon.Lambda.Core" Version="2.1.0" />
    <PackageReference Include="Amazon.Lambda.SQSEvents" Version="2.1.0" />
    <PackageReference Include="Amazon.Lambda.Serialization.Json" Version="2.1.0" />
    <PackageReference Include="AWSSDK.Core" Version="3.7.103.24" />
    <PackageReference Include="AWSSDK.Lambda" Version="3.7.104.3" />
    <PackageReference Include="AWSXRayRecorder.Core" Version="2.13.0" />
    <PackageReference Include="AWSXRayRecorder.Handlers.AwsSdk" Version="2.11.0" />
  </ItemGroup>
</Project>
```

有一系列的 Nuget 套件提供自動檢測 AWS SDKs、實體架構和 HTTP 請求。若要查看完整的組態選項集，請參閱《AWS X-Ray 開發人員指南》**中的[適用於 .NET 的AWS X-Ray SDK](https://docs.aws.amazon.com/xray/latest/devguide/xray-sdk-dotnet.html)。

新增所需的 Nuget 套件後，請設定自動檢測。最佳實務是在函數的處理常式函數之外執行此設定。這麼做可讓您利用執行環境重新使用來改善函數的效能。在下列程式碼範例中，在函數建構函數中呼叫 `RegisterXRayForAllServices`方法，以新增所有 AWS SDK 呼叫的檢測。

```
[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))]

namespace GetProductHandler;

public class Function
{
    private readonly IDatabaseRepository _repo;
    
    public Function()
    {
        // Add auto instrumentation for all AWS SDK calls
        // It is important to call this method before initializing any SDK clients
        AWSSDKHandler.RegisterXRayForAllServices();
        this._repo = new DatabaseRepository();
    }
    
    public async Task<APIGatewayProxyResponse> FunctionHandler(APIGatewayProxyRequest request)
    {
        var id = request.PathParameters["id"];
        
        var databaseRecord = await this._repo.GetById(id);
        
        return new APIGatewayProxyResponse 
        {
            StatusCode = (int)HttpStatusCode.OK,
            Body = JsonSerializer.Serialize(databaseRecord)
        };
    }
}
```

## 透過 Lambda 主控台來啟用追蹤
<a name="dotnet-tracing-console"></a>

若要使用控制台在 Lambda 函數上切換主動追蹤，請按照下列步驟操作：

**開啟主動追蹤**

1. 開啟 Lambda 主控台中的 [函數頁面](https://console.aws.amazon.com/lambda/home#/functions)。

1. 選擇一個函數。

1. 選擇**組態**，然後選擇**監控和操作工具**。

1. 在**其他監控工具**欄位中，選擇**編輯**。

1. 在 **CloudWatch Application Signals 和 AWS X-Ray** 下，選擇**啟用** **Lambda 服務追蹤**。

1. 選擇**儲存**。

## 透過 Lambda API 啟用追蹤
<a name="dotnet-tracing-api"></a>

使用 AWS CLI 或 AWS SDK 在 Lambda 函數上設定追蹤，請使用下列 API 操作：
+ [UpdateFunctionConfiguration](https://docs.aws.amazon.com/lambda/latest/api/API_UpdateFunctionConfiguration.html)
+ [GetFunctionConfiguration](https://docs.aws.amazon.com/lambda/latest/api/API_GetFunctionConfiguration.html)
+ [CreateFunction](https://docs.aws.amazon.com/lambda/latest/api/API_CreateFunction.html)

下列範例 AWS CLI 命令會在名為 **my-function** 的函數上啟用主動追蹤。

```
aws lambda update-function-configuration --function-name my-function \
--tracing-config Mode=Active
```

追蹤模式是您發布函數版本時版本特定組態的一部分。您無法變更已發佈版本上的追蹤模式。

## 使用 啟用追蹤 CloudFormation
<a name="dotnet-tracing-cloudformation"></a>

若要在 CloudFormation 範本中的 `AWS::Lambda::Function` 資源上啟用追蹤，請使用 `TracingConfig` 屬性。

**Example [function-inline.yml](https://github.com/awsdocs/aws-lambda-developer-guide/blob/master/templates/function-inline.yml) - 追蹤組態**  

```
Resources:
  function:
    Type: [AWS::Lambda::Function](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-function.html)
    Properties:
      TracingConfig:
        Mode: Active
      ...
```

對於 AWS Serverless Application Model (AWS SAM) `AWS::Serverless::Function` 資源，請使用 `Tracing` 屬性。

**Example [template.yml](https://github.com/awsdocs/aws-lambda-developer-guide/tree/main/sample-apps/blank-nodejs/template.yml) - 追蹤組態**  

```
Resources:
  function:
    Type: [AWS::Serverless::Function](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-resource-function.html)
    Properties:
      Tracing: Active
      ...
```

## 解讀 X-Ray 追蹤
<a name="dotnet-tracing-interpretation"></a>

您的函數需要將追蹤資料上傳至 X-Ray 的許可。當您在 Lambda 主控台中啟用追蹤時，Lambda 會將必要的許可新增至函數的[執行角色](lambda-intro-execution-role.md)。否則，請將 [AWSXRayDaemonWriteAccess](https://console.aws.amazon.com/iam/home#/policies/arn:aws:iam::aws:policy/AWSXRayDaemonWriteAccess) 政策新增至執行角色。

設定主動追蹤之後，您可以透過應用程式來觀察特定請求。[X-Ray 服務圖](https://docs.aws.amazon.com/xray/latest/devguide/aws-xray.html#xray-concepts-servicegraph)顯示了有關應用程式及其所有元件的資訊。下列範例顯示了一個具有兩個函數的應用程式。主要函式會處理事件，有時會傳回錯誤。頂端的第二個函數會處理出現在第一個日誌群組中的錯誤，並使用 AWS SDK 呼叫 X-Ray、Amazon Simple Storage Service (Amazon S3) 和 Amazon CloudWatch Logs。

![\[\]](http://docs.aws.amazon.com/zh_tw/lambda/latest/dg/images/sample-errorprocessor-servicemap.png)


X-Ray 無法追蹤應用程式的所有請求。X-Ray 會套用取樣演算法以確保追蹤的效率，同時仍提供所有請求的代表範本。取樣率為每秒 1 次請求和 5% 的額外請求。不能針對函數設定 X-Ray 取樣率。

在 X-Ray 中，*追蹤*會記錄一或多個*服務*所處理之要求的相關資訊。Lambda 會在每個追蹤上記錄 2 個區段，這會在服務圖表上建立兩個節點。下圖反白顯示了這兩個節點：

![\[\]](http://docs.aws.amazon.com/zh_tw/lambda/latest/dg/images/xray-servicemap-function.png)


左側第一個節點代表接收調用請求的 Lambda 服務。第二個節點代表您特定的 Lambda 函數。下列範例顯示了具有這 2 個區段的追蹤。兩者都被命名為 **my-function**，但其中之一的來源為 `AWS::Lambda`，而另一個的來源為 `AWS::Lambda::Function`。如果 `AWS::Lambda` 區段顯示錯誤，Lambda 服務就會出現問題。如果 `AWS::Lambda::Function` 區段顯示錯誤，表示您的函數出現了問題。

![\[\]](http://docs.aws.amazon.com/zh_tw/lambda/latest/dg/images/V2_sandbox_images/my-function-2-v1.png)


此範例會展開 `AWS::Lambda::Function` 區段以顯示其三個子區段：

**注意**  
AWS 目前正在對 Lambda 服務實作變更。由於這些變更，您可能會看到系統日誌訊息的結構和內容，與 AWS 帳戶中不同 Lambda 函數發出的追蹤區段之間存在細微差異。  
此處顯示的追蹤範例說明了舊式函數區段。下列段落說明了舊式和新式區段之間的差異。  
這些變化將在未來幾週內實作，除中國和 GovCloud 區域以外，所有 AWS 區域 中的所有函數都會轉換至使用新格式的日誌訊息和追蹤區段。

舊式函數區段包含下列子區段：
+ **初始化** - 表示載入函數和執行[初始化程式碼](foundation-progmodel.md)所花費的時間。只有函數的每個執行個體所處理的第一個事件會顯示此子區段。
+ **調用** – 表示執行處理常式程式碼所花費的時間。
+ **額外負荷** - 表示 Lambda 執行期為做好準備以處理下一個事件所花費的時間。

新式函數區段不包含 `Invocation` 子區段。相反地，客戶子區段會直接連接至函數區段。如需舊式和新式函數區段結構的詳細資訊，請參閱[了解 X-Ray 追蹤](services-xray.md#services-xray-traces)。

您也可以檢測 HTTP 用戶端、記錄 SQL 查詢，以及建立具有註釋和中繼資料的自訂子區段。如需詳細資訊，請參閱《*AWS X-Ray 開發人員指南*》中的 [適用於 .NET 的 AWS X-Ray SDK](https://docs.aws.amazon.com/xray/latest/devguide/xray-sdk-dotnet.html) 許可。

**定價**  
您可以在每月免費使用 X-Ray 追蹤，最高可達特定限制，作為 AWS 免費方案的一部分。達到閾值後，X-Ray 會收取追蹤儲存及擷取的費用。如需詳細資訊，請參閱 [AWS X-Ray 定價](https://aws.amazon.com/xray/pricing/)。

# 以 C\$1 測試 AWS Lambda 函數
<a name="dotnet-csharp-testing"></a>

**注意**  
如需測試無伺服器解決方案之技術和最佳實務的完整介紹，請參閱[測試函數](testing-guide.md)章節。

 測試無伺服器函數會使用傳統的測試類型和技術，但您也必須考慮測試整個無伺服器應用程式。以雲端為基礎的測試會為您的函數和無伺服器應用程式提供**最準確的**品質測量標準。

 無伺服器應用程式架構包括透過 API 呼叫提供關鍵應用程式功能的受管服務。因此，您的開發週期應包括自動化測試，以便在函數和服務互動時驗證功能。

 如果您未建立以雲端為基礎的測試，則可能會因本機環境與部署環境之間的差異而遇到問題。您的持續整合程序應先針對雲端佈建的一組資源進行測試，然後再將程式碼升級至下一個部署環境 (例如 QA、暫存或生產環境)。

 繼續閱讀這份簡短指南，了解無伺服器應用程式的測試策略，或造訪[無伺服器測試範例儲存庫](https://github.com/aws-samples/serverless-test-samples)，深入了解所選語言和執行期的特定實際範例。

 ![\[illustration showing the relationship between types of tests\]](http://docs.aws.amazon.com/zh_tw/lambda/latest/dg/images/test-type-illustration2.png) 

 若為無伺服器測試，您仍需要寫入*單元*、*整合*及*端對端*測試。
+ **單元測試**：針對一組隔離的程式碼區塊進行的測試。例如，驗證商業邏輯以計算指定的特定項目與目的地的運費。
+ **整合測試**：涉及到兩個以上元件或服務進行互動的測試 (通常在雲端環境)。例如，驗證函數是否有處理佇列中的事件。
+ **端對端測試**：驗證整個應用程式行為的測試。例如，確保基礎設施的設定正確無誤，以及事件如預期在服務之間流動，以記錄客戶的訂單。

## 測試無伺服器應用程式
<a name="dotnet-csharp-testing-techniques-for-serverless-applications"></a>

 通常會混合使用多種方法來測試無伺服器應用程式程式碼，包括在雲端進行測試、透過模擬物件進行測試，以及偶爾使用模擬器進行測試。

### 在雲端進行測試
<a name="dotnet-csharp-testing-in-the-cloud"></a>

 在雲端進行測試對所有測試階段 (包括單元測試、整合測試和端對端測試) 來說都很有價值。您可以針對部署在雲端中的程式碼執行測試，並與雲端服務互動。這是**最準確**的程式碼品質測量方法。

 您可以透過主控台使用測試事件，輕鬆在雲端對 Lambda 函數進行偵錯。一個*測試事件*是函數的 JSON 輸入。如果您的函數不需要輸入，該事件可以是空白的 JSON 文件 `({})`。主控台提供各種服務整合的範例事件。在主控台中建立事件後，您可以與團隊分享事件，讓測試變得更容易，結果更一致。

**注意**  
在[控制台中測試函數](testing-functions.md)是簡便快速的入門方式，而將測試週期自動化可確保應用程式的品質和開發速度。

### 測試工具
<a name="dotnet-csharp-testing-tools"></a>

為了加速開發週期，您可以在測試函數時使用多種工具和技巧。例如，[AWS SAM Accelerate](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/using-sam-cli-sync.html) 和 [AWS CDK 監看模式](https://docs.aws.amazon.com/cdk/v2/guide/cli.html#cli-deploy-watch)都可以縮短更新雲端環境所需的時間。

您定義 Lambda 函數程式碼的方式，讓您可輕鬆加入單元測試。Lambda 需要使用公有無參數建構函數來初始化類別。引入第二個內部建構函數，可讓您控制應用程式使用的相依項。

```
[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))]

namespace GetProductHandler;

public class Function
{
    private readonly IDatabaseRepository _repo;
    
    public Function(): this(null)
    {
    }
    
    internal Function(IDatabaseRepository repo)
    {
        this._repo = repo ?? new DatabaseRepository();
    }
    
    public async Task<APIGatewayProxyResponse> FunctionHandler(APIGatewayProxyRequest request)
    {
        var id = request.PathParameters["id"];
        
        var databaseRecord = await this._repo.GetById(id);
        
        return new APIGatewayProxyResponse 
        {
            StatusCode = (int)HttpStatusCode.OK,
            Body = JsonSerializer.Serialize(databaseRecord)
        };
    }
}
```

若要為此函數編寫測試，您可以初始化 `Function` 類別的新執行個體，並傳入 `IDatabaseRepository` 的模擬實作。以下範例使用 `XUnit`、`Moq` 和 `FluentAssertions` 來編寫簡單的測試，確保 `FunctionHandler` 會傳回 200 狀態碼。

```
using Xunit;
using Moq;
using FluentAssertions;

public class FunctionTests
{
    [Fact]
    public async Task TestLambdaHandler_WhenInputIsValid_ShouldReturn200StatusCode()
    {
        // Arrange
        var mockDatabaseRepository = new Mock<IDatabaseRepository>();
        
        var functionUnderTest = new Function(mockDatabaseRepository.Object);
        
        // Act
        var response = await functionUnderTest.FunctionHandler(new APIGatewayProxyRequest());
        
        // Assert
        response.StatusCode.Should().Be(200);
    }
}
```

如需更詳細的範例，包括非同步測試範例在內，請參閱 GitHub 上的 [.NET 測試範例儲存庫](https://github.com/aws-samples/serverless-test-samples/tree/main/dotnet-test-samples)。