本文為英文版的機器翻譯版本,如內容有任何歧義或不一致之處,概以英文版為準。
以 C# 編寫的 Lambda 函數處理常式
Lambda 函數處理常式是您的函數程式碼中處理事件的方法。當有人呼叫您的函數時,Lambda 會執行處理常式方法。函數會執行,直到處理常式傳回回應、結束或逾時為止。
當您的函數遭調用,且 Lambda 執行了函數的處理常式方法時,系統會將兩個引數傳遞給函數。第一個引數是 event
物件。當另一個 AWS 服務 調用您的函數時,該event
對象包含有關導致您的函數被調用的事件的數據。例如,來自 API Gateway 的 event
物件中,包含路徑、HTTP 方法和 HTTP 標頭的相關資訊。確切的事件結構根據 AWS 服務 調用函數而有所不同。如需個別服務事件格式的詳細資訊,請參閱:AWS Lambda 搭配其他服務使用。
Lambda 也會傳遞 context
物件給函數。此物件包含有關調用、函數以及執行環境的資訊。如需詳細資訊,請參閱 C# 中的 AWS Lambda 內容物件。
所有 Lambda 事件的原生格式,都是代表 JSON 格式事件的位元組串流。除非您的函數輸入與輸出參數為 System.IO.Stream
類型,否則必須將其序列化。透過設定 LambdaSerializer
組件屬性來指定要使用的序列化程式。如需詳細資訊,請參閱 Lambda 函數中的序列化。
主題
適用於 Lambda 的 .NET 執行模型
在 .NET 中執行 Lambda 函數有兩種不同的執行模型:類別庫和可執行組件做法。
若使用類別庫做法,您可以為 Lambda 提供一個字串,指出要調用之函數的 AssemblyName
、ClassName
、和 Method
。如需此字串格式的詳細資訊,請參閱:類別庫處理常式。在函數的初始化階段,系統會初始化函數的類別,並執行建構函數中的任何程式碼。
若使用可執行組件做法,您可以使用 C# 9 的頂層陳述式
以下各節提供這兩種做法的範例函數程式碼。
類別庫處理常式
下列 Lambda 函數程式碼顯示使用類別庫做法之 Lambda 函數的處理常式方法 (FunctionHandler
) 範例。在此範例函數中,Lambda 收到調用函數的 API Gateway 傳來的事件。函數會從資料庫讀取記錄,並在 API Gateway 回應中傳回該記錄。
[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) { var id = request.PathParameters["id"]; var databaseRecord = await this._repo.GetById(id); return new APIGatewayProxyResponse { StatusCode = (int)HttpStatusCode.OK, Body = JsonSerializer.Serialize(databaseRecord) }; } }
建立 Lambda 函數時,您需要以處理常式字串的形式向 Lambda 提供函數處理常式的相關資訊。目的是指示 Lambda 在調用函數時要在程式碼中執行哪種方法。若使用 C#,使用類別庫做法時處理常式字串的格式如下:
ASSEMBLY::TYPE::METHOD
,其中:
-
ASSEMBLY
是應用程式的 .NET 組件名稱。如果您使用Amazon.Lambda.Tools
CLI 建置應用程式,而沒有使用 .csproj 檔案中的AssemblyName
屬性來設定組件名稱,則ASSEMBLY
單純為 .csproj 檔案的名稱。 -
TYPE
是處理常式類型的完整名稱,包含Namespace
和ClassName
。 -
METHOD
是程式碼中函數處理常式方法的名稱。
在顯示的範例程式碼中,如果組件名為 GetProductHandler
,則處理常式字串會是 GetProductHandler::GetProductHandler.Function::FunctionHandler
。
可執行組件處理常式
在下列範例中,Lambda 函數定義為可執行的組件。此程式碼中的處理常式方法名為 Handler
。使用可執行組件時,必須引導 Lambda 執行期。若要執行此作業,請使用 LambdaBootstrapBuilder.Create
方法。此方法的輸入是函數當成處理常式使用的方法,以及要使用的 Lambda 序列化程式。
如需有關使用頂層陳述式的詳細資訊,請參閱 AWS 運算部落格 AWS Lambda上的 .NET 6 執行階段簡介
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 = input.PathParameters["id"]; var databaseRecord = await this.repo.GetById(id); return new APIGatewayProxyResponse { StatusCode = (int)HttpStatusCode.OK, Body = JsonSerializer.Serialize(databaseRecord) }; };
使用可執行組件時,指示 Lambda 如何執行程式碼的處理常式字串就是組件的名稱。在這個範例中,即為 GetProductHandler
。
Lambda 函數中的序列化
若您的 Lambda 函數使用輸入或輸出類型而非 Stream
物件,您必須將序列化程式庫新增至您的應用程式。若要實作序列化,您可以使用 System.Text.Json
和 Newtonsoft.Json
提供的標準反射式序列化,或是使用原始碼產生的序列化
使用原始碼產生的序列化
源代碼生成的序列化是 .NET 版本 6 及更高版本的功能,允許在編譯時生成序列化代碼。此方式不需要使用反射,且可提高函數的效能。若要在函數中使用原始碼產生的序列化,請執行以下操作:
-
建立一個繼承自
JsonSerializerContext
的新部分分類,為需要序列化或還原序列化的所有類型新增JsonSerializable
屬性。 -
設定
LambdaSerializer
以使用SourceGeneratorLambdaJsonSerializer<T>
。 -
更新應用程式程式碼中的任何手動序列化或還原序列化,以使用新建立的類別。
以下程式碼顯示的範例函數,是使用原始碼產生的序列化。
[assembly: LambdaSerializer(typeof(SourceGeneratorLambdaJsonSerializer<CustomSerializer>))] public class Function { private readonly IDatabaseRepository _repo; public Function() { 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, CustomSerializer.Default.Product) }; } } [JsonSerializable(typeof(APIGatewayProxyRequest))] [JsonSerializable(typeof(APIGatewayProxyResponse))] [JsonSerializable(typeof(Product))] public partial class CustomSerializer : JsonSerializerContext { }
注意
如果您想透過 Lambda 使用原生預先編譯 (AOT),必須使用原始碼產生的序列化。
使用反射式序列化
AWS 提供預先建置的程式庫,讓您快速將序列化新增至應用程式。您可以使用Amazon.Lambda.Serialization.SystemTextJson
或Amazon.Lambda.Serialization.Json
NuGet 套件來設定此項目。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 作業傳回的回應承載中。
使用 Lambda Annotations 架構簡化函數程式碼
Lambda 註解是 .NET 6 和 .NET 8 的框架,它簡化了使用 C# 編寫 Lambda 函數的過程。透過 Annotations 架構,您可以取代使用一般程式設計模型編寫的大部分 Lambda 函數程式碼。使用此架構編寫的程式碼使用更簡單的表達式,讓您可專注於商業邏輯。
以下範例程式碼示範使用 Annotations 架構可如何簡化編寫 Lambda 函數的程序。第一個範例顯示使用一般 Lambda 程式模型編寫的程式碼,第二個範例顯示使用 Annotations 架構的對等程式碼。
public APIGatewayHttpApiV2ProxyResponse LambdaMathAdd(APIGatewayHttpApiV2ProxyRequest request, ILambdaContext context) { if (!request.PathParameters.TryGetValue("x", out var xs)) { return new APIGatewayHttpApiV2ProxyResponse { StatusCode = (int)HttpStatusCode.BadRequest }; } if (!request.PathParameters.TryGetValue("y", out var ys)) { return new APIGatewayHttpApiV2ProxyResponse { StatusCode = (int)HttpStatusCode.BadRequest }; } var x = int.Parse(xs); var y = int.Parse(ys); return new APIGatewayHttpApiV2ProxyResponse { StatusCode = (int)HttpStatusCode.OK, Body = (x + y).ToString(), Headers = new Dictionary≪string, string> { { "Content-Type", "text/plain" } } }; }
[LambdaFunction] [HttpApi(LambdaHttpMethod.Get, "/add/{x}/{y}")] public int Add(int x, int y) { return x + y; }
如需使用 Lambda 註解如何簡化程式碼的另一個範例,請參閱awsdocs/aws-doc-sdk-examples
GitHub 儲存庫中的這個跨服務範例應PamApiAnnotations
資料夾在主要 function.cs
檔案中使用 Lambda Annotations。為了進行比較,PamApi
資料夾包含使用一般 Lambda 程式設計模型編寫的對等檔案。
Annotations 架構使用原始碼產生器
如需如何使用 Lambda Annotations for .NET 的詳細資訊,請參閱下列資源:
-
存
aws/aws-lambda-dotnet
GitHub 放庫。 -
在 AWS 開發人員工具部落格中介紹 .NET 註解 Lambda 架構 (預覽版)
。 -
包
Amazon.Lambda.Annotations
NuGet 裝。
使用 Lambda Annotations 架構進行相依性插入
您也可以透過 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); } }
Lambda 函數處理常式限制
請注意,處理常式簽章有若干限制。
-
處理常式簽章不能為
unsafe
,且不得使用指標類型,但可以在處理函式方法及其依存項目中使用unsafe
內容。如需詳細資訊,請參閱 Microsoft 文檔網站上的不安全 (C# 參考)。 -
處理常式不會傳送使用
params
關鍵字的參數變數,也不得使用支援參數變數的ArgIterator
作為輸入或傳回參數。 -
處理常式不得為通用方法,例如 IList<T> Sort<T>(IList<T> input)。
-
不支援具有
async void
簽章的非同步處理常式。