Definieren Sie den Lambda-Funktionshandler in C# - AWS Lambda

Die vorliegende Übersetzung wurde maschinell erstellt. Im Falle eines Konflikts oder eines Widerspruchs zwischen dieser übersetzten Fassung und der englischen Fassung (einschließlich infolge von Verzögerungen bei der Übersetzung) ist die englische Fassung maßgeblich.

Definieren Sie den Lambda-Funktionshandler in C#

Der Lambda-Funktionshandler ist die Methode in Ihrem Funktionscode, die Ereignisse verarbeitet. Wenn Ihre Funktion aufgerufen wird, führt Lambda die Handler-Methode aus. Ihre Funktion wird so lange ausgeführt, bis der Handler eine Antwort zurückgibt, beendet wird oder ein Timeout auftritt.

Wenn Ihre Funktion aufgerufen wird und Lambda die Handler-Methode Ihrer Funktion ausführt, übergibt es zwei Argumente an Ihre Funktion. Das erste Argument ist das event-Objekt. Wenn eine andere Funktion Ihre Funktion AWS-Service aufruft, enthält das event Objekt Daten über das Ereignis, das den Aufruf Ihrer Funktion verursacht hat. Ein event Objekt von API Gateway enthält beispielsweise Informationen über den Pfad, die HTTP Methode und HTTP die Header. Die genaue Ereignisstruktur hängt davon ab, wie Ihre AWS-Service Funktion aufgerufen wird. Weitere Informationen zu Veranstaltungsformaten für einzelne Dienste finden Sie unter Lambda mit Ereignissen aus anderen Diensten aufrufen AWS.

Lambda übergibt auch ein context-Objekt an Ihre Funktion. Dieses Objekt enthält Informationen über den Aufruf, die Funktion und die Ausführungsumgebung. Weitere Informationen finden Sie unter Verwenden des Lambda-Kontextobjekts zum Abrufen von C#-Funktionsinformationen.

Das native Format für alle Lambda-Ereignisse sind Bytestreams, die das JSON formatierte Ereignis darstellen. Wenn Ihre Funktionseingabe- und Ausgabeparameter nicht vom Typ System.IO.Stream sind, müssen Sie sie serialisieren. Geben Sie den zu verwendenden Serialisierer an, indem Sie das Assembly-Attribut LambdaSerializer setzen. Weitere Informationen finden Sie unter Serialisieren von Lambda-Funktionen.

. NETAusführungsmodelle für Lambda

Es gibt zwei verschiedene Ausführungsmodelle für die Ausführung von Lambda-Funktionen in. NET: der Klassenbibliothek-Ansatz und der Ansatz für ausführbare Assemblys.

Beim Ansatz der Klassenbibliothek übermitteln Sie Lambda eine Zeichenfolge mit den Angaben AssemblyName, ClassName, und Method der aufzurufenden Funktion. Weitere Informationen über das Format dieser Zeichenfolge finden Sie unter Handler für Klassenbibliotheken. Während der Initialisierungsphase der Funktion wird die Klasse Ihrer Funktion initialisiert und der gesamte Code im Konstruktor wird ausgeführt.

Beim Ansatz für ausführbare Assemblys verwenden Sie das Feature für Anweisungen der obersten Ebene von C# 9. Dieser Ansatz generiert eine ausführbare Assembly, die Lambda immer dann ausführt, wenn sie einen Aufrufbefehl für Ihre Funktion empfängt. Sie geben Lambda nur den Namen der ausführbaren Assembly an, die ausgeführt werden soll.

Die folgenden Abschnitte enthalten Beispielfunktionscode für diese beiden Ansätze.

Handler für Klassenbibliotheken

Der folgende Lambda-Funktionscode zeigt ein Beispiel für eine Handler-Methode (FunctionHandler) für eine Lambda-Funktion, die den Klassenbibliotheksansatz verwendet. In dieser Beispielfunktion empfängt Lambda ein Ereignis von API Gateway, das die Funktion aufruft. Die Funktion liest einen Datensatz aus einer Datenbank und gibt den Datensatz als Teil der API Gateway-Antwort zurück.

[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) }; } }

Wenn Sie eine Lambda-Funktion erstellen, müssen Sie Lambda Informationen über den Handler Ihrer Funktion in Form eines Handler-Strings zur Verfügung stellen. Dadurch wird Lambda mitgeteilt, welche Methode in Ihrem Code ausgeführt werden soll, wenn Ihre Funktion aufgerufen wird. In C# lautet das Format der Handlerzeichenfolge bei Verwendung des Klassenbibliotheksansatzes wie folgt:

ASSEMBLY::TYPE::METHOD, wobei:

  • ASSEMBLYist der Name des. NETAssemblerdatei für Ihre Anwendung. Wenn Sie die Amazon.Lambda.Tools CLI zum Erstellen Ihrer Anwendung verwenden und den Assemblynamen nicht mithilfe der AssemblyName Eigenschaft in der CSPROJ-Datei festlegen, dann ASSEMBLY ist das einfach der Name Ihrer CSPROJ-Datei.

  • TYPE ist der vollständige Name des Handler-Typs, der aus Namespace und ClassName besteht.

  • METHOD ist der Name der Funktionshandlermethode in Ihrem Code.

Wenn die Baugruppe im Beispielcode den Namen GetProductHandler trägt, lautet die Zeichenfolge für den Handler GetProductHandler::GetProductHandler.Function::FunctionHandler.

Ausführbare Assembly-Handler

Im folgenden Beispiel ist die Lambda-Funktion als ausführbare Assembly definiert. Die Handler-Methode in diesem Code heißt Handler. Bei der Verwendung ausführbarer Assemblys muss die Lambda-Laufzeit gebootet werden. Dazu verwenden Sie die LambdaBootstrapBuilder.Create-Methode. Diese Methode nimmt als Eingaben die Methode, die Ihre Funktion als Handler verwendet, und den zu verwendenden Lambda-Serializer entgegen.

Weitere Informationen zur Verwendung von Anweisungen auf oberster Ebene finden Sie unter Einführung in die. NET6 Runtime for AWS Lambda im AWS Compute-Blog.

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

Bei der Verwendung von ausführbaren Assemblys ist der Handler-String, der Lambda mitteilt, wie Ihr Code ausgeführt werden soll, der Name der Assembly. In diesem Beispiel wäre das GetProductHandler.

Serialisieren von Lambda-Funktionen

Wenn Ihre Lambda-Funktion andere Eingabe- oder Ausgabetypen als ein Stream-Objekt verwendet, müssen Sie eine Serialisierungsbibliothek zu Ihrer Anwendung hinzufügen. Sie können die Serialisierung entweder mit der standardmäßigen reflexionsbasierten Serialisierung implementieren, die von System.Text.Json und Newtonsoft.Json bereitgestellt wird, oder mit der quellgenerierten Serialisierung.

Verwenden Sie die durch die Quelle generierte Serialisierung

Die von der Quelle generierte Serialisierung ist eine Funktion von. NETVersionen 6 und höher, mit denen Serialisierungscode zur Kompilierzeit generiert werden kann. Sie macht Reflexionen überflüssig und kann die Leistung Ihrer Funktion verbessern. Gehen Sie wie folgt vor, um die quellgenerierte Serialisierung in Ihrer Funktion zu verwenden:

  • Erstellen Sie eine neue Teilklasse, die von JsonSerializerContext erbt, und fügen Sie JsonSerializable-Attribute für alle Typen hinzu, die serialisiert oder deserialisiert werden müssen.

  • Konfigurieren Sie das LambdaSerializer so, dass es ein SourceGeneratorLambdaJsonSerializer<T> verwendet.

  • Aktualisieren Sie alle manuellen Serialisierungen oder Deserialisierungen in Ihrem Anwendungscode, um die neu erstellte Klasse zu verwenden.

Eine Beispielfunktion, die quellgenerierte Serialisierung verwendet, wird im folgenden Code gezeigt.

[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 { }
Anmerkung

Wenn Sie die native Ahead-of-Time-Compilation (AOT) mit Lambda verwenden möchten, müssen Sie die quellgenerierte Serialisierung verwenden.

Verwenden Sie die reflektionsbasierte Serialisierung

AWS stellt vorgefertigte Bibliotheken bereit, mit denen Sie Ihrer Anwendung schnell Serialisierung hinzufügen können. Sie konfigurieren dies entweder mit den Paketen Amazon.Lambda.Serialization.SystemTextJson oder Amazon.Lambda.Serialization.Json NuGet . Hinter den Kulissen verwendet Amazon.Lambda.Serialization.SystemTextJson System.Text.Json, um Serialisierungsaufgaben durchzuführen, und Amazon.Lambda.Serialization.Json verwendet das Paket Newtonsoft.Json.

Sie können auch Ihre eigene Serialisierungsbibliothek erstellen, indem Sie die ILambdaSerializer-Schnittstelle implementieren; diese ist als Teil der Amazon.Lambda.Core-Bibliothek verfügbar. Diese Schnittstelle definiert zwei Methoden:

  • T Deserialize<T>(Stream requestStream);

    Sie implementieren diese Methode, um die Anforderungsnutzlast vom Invoke API in das Objekt zu deserialisieren, das an Ihren Lambda-Funktionshandler übergeben wird.

  • T Serialize<T>(T response, Stream responseStream);

    Sie implementieren diese Methode, um das von Ihrem Lambda-Funktionshandler zurückgegebene Ergebnis in die Antwortnutzlast zu serialisieren, die der Vorgang zurückgibt. Invoke API

Vereinfachen Sie den Funktionscode mit dem Lambda Annotations Framework

Lambda Annotations ist ein Framework für. NET6 und. NET8, was das Schreiben von Lambda-Funktionen mit C# vereinfacht. Mit dem Annotations-Framework können Sie einen Großteil des Codes in einer Lambda-Funktion ersetzen, die mit dem regulären Programmiermodell geschrieben wurde. Code, der mit dem Framework geschrieben wurde, verwendet einfachere Ausdrücke, sodass Sie sich auf Ihre Geschäftslogik konzentrieren können.

Der folgende Beispielcode zeigt, wie die Verwendung des Annotations-Frameworks das Schreiben von Lambda-Funktionen vereinfachen kann. Das erste Beispiel zeigt Code, der mit dem regulären Lambda-Programmmodell geschrieben wurde, und das zweite zeigt das Äquivalent unter Verwendung des Annotations-Frameworks.

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

Ein weiteres Beispiel dafür, wie die Verwendung von Lambda-Anmerkungen Ihren Code vereinfachen kann, finden Sie in dieser serviceübergreifenden Beispielanwendung im Repository. awsdocs/aws-doc-sdk-examples GitHub Der Ordner PamApiAnnotations verwendet Lambda-Anmerkungen in der function.cs-Hauptdatei. Zum Vergleich: Der PamApi-Ordner enthält äquivalente Dateien, die mit dem regulären Lambda-Programmiermodell geschrieben wurden.

Das Annotations-Framework verwendet Quellgeneratoren, um Code zu generieren, der vom Lambda-Programmiermodell in den Code aus dem zweiten Beispiel übersetzt wird.

Weitere Informationen zur Verwendung von Lambda-Annotationen für. NET, finden Sie in den folgenden Ressourcen:

Abhängigkeitsinjektion mit dem Lambda Annotations-Framework

Sie können auch das Lambda Annotations-Framework verwenden, um Ihren Lambda-Funktionen eine Dependency Injection hinzuzufügen, indem Sie die Syntax verwenden, mit der Sie vertraut sind. Wenn Sie einer [LambdaStartup]-Datei ein Startup.cs-Attribut hinzufügen, generiert das Lambda Annotations-Framework den erforderlichen Code zur Kompilierzeit.

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

Ihre Lambda-Funktion kann Dienste entweder durch Konstruktorinjektion oder durch Injektion in einzelne Methoden unter Verwendung des [FromServices]-Attributs injizieren.

[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); } }

Einschränkungen des Lambda-Funktionshandlers

Beachten Sie, dass für die Handlersignatur einige Einschränkungen bestehen.

  • Möglicherweise ist es nicht unsafe, Pointer-Typen in der Handler-Signatur zu verwenden, Sie können jedoch unsafe-Kontext in der Handler-Methode und ihren Abhängigkeiten verwenden. Weitere Informationen finden Sie unter unsafe (C#-Referenz) auf der Microsoft-Docs-Website.

  • Eine variable Anzahl von Parametern kann nicht mit dem Schlüsselwort params weitergegeben werden und ArgIterator kann nicht als Eingabe- oder Rückgabe-Parameter verwendet werden, der zur Unterstützung einer variablen Anzahl von Parametern verwendet wird.

  • Bei dem Handler handelt es sich möglicherweise nicht um eine generische Methode, z. B. IList <T>Sort <T>(IList<T>Eingabe).

  • Asynchrone Handler mit der Signatur async void werden nicht unterstützt.

Bewährte Codemethoden für C#-Lambda-Funktionen

Halten Sie sich an die Richtlinien in der folgenden Liste, um beim Erstellen Ihrer Lambda-Funktionen die besten Codierungspraktiken anzuwenden:

  • Trennen Sie den Lambda-Handler von Ihrer Core-Logik. Auf diese Weise können Sie eine Funktion zur besseren Prüfbarkeit von Einheiten schaffen.

  • Kontrollieren Sie die Abhängigkeiten im Bereitstellungspaket Ihrer Funktion. Die AWS Lambda Ausführungsumgebung enthält eine Reihe von Bibliotheken. Um die neuesten Funktionen und Sicherheitsupdates zu aktivieren, wird Lambda diese Bibliotheken regelmäßig aktualisieren. Diese Updates können das Verhalten Ihrer Lambda-Funktion geringfügig verändern. Um die Abhängigkeiten, die Ihre Funktion verwendet, vollständig zu kontrollieren, empfehlen wir, alle Abhängigkeiten mit Ihrem Bereitstellungspaket zu bündeln.

  • Minimieren Sie die Komplexität Ihrer Abhängigkeiten. Ziehen Sie einfachere Frameworks vor, die sich schnell beim Start der Ausführungsumgebung laden lassen.

  • Minimieren Sie die Größe Ihres Bereitstellungspakets auf die für die Laufzeit erforderliche Größe. Dadurch verkürzt sich die Zeit, die für das Herunterladen und Entpacken Ihres Bereitstellungspakets vor dem Aufruf benötigt wird. Für Funktionen, die in verfasst wurden. NET, vermeiden Sie es, die gesamte AWS SDK Bibliothek als Teil Ihres Bereitstellungspakets hochzuladen. Verlassen SDK Sie sich stattdessen selektiv auf die Module, die die benötigten Komponenten aufnehmen (z. B. DynamoDB, Amazon S3 SDK S3-Module und Lambda-Kernbibliotheken).

  • Nutzen Sie die Wiederverwendung der Ausführungsumgebung zur Verbesserung Ihrer Funktion. Initialisieren Sie SDK Clients und Datenbankverbindungen außerhalb des Funktionshandlers und speichern Sie statische Ressourcen lokal im Verzeichnis. /tmp Nachfolgende Aufrufe, die von derselben Instance Ihrer Funktion verarbeitet werden, können diese Ressourcen wiederverwenden. Dies spart Kosten durch Reduzierung der Funktionslaufzeit.

    Um potenzielle Datenlecks über Aufrufe hinweg zu vermeiden, verwenden Sie die Ausführungsumgebung nicht, um Benutzerdaten, Ereignisse oder andere Informationen mit Sicherheitsauswirkungen zu speichern. Wenn Ihre Funktion auf einem veränderbaren Zustand beruht, der nicht im Speicher innerhalb des Handlers gespeichert werden kann, sollten Sie für jeden Benutzer eine separate Funktion oder separate Versionen einer Funktion erstellen.

  • Verwenden Sie eine Keep-Alive-Direktive, um dauerhafte Verbindungen zu pflegen. Lambda bereinigt Leerlaufverbindungen im Laufe der Zeit. Der Versuch, eine Leerlaufverbindung beim Aufruf einer Funktion wiederzuverwenden, führt zu einem Verbindungsfehler. Um Ihre persistente Verbindung aufrechtzuerhalten, verwenden Sie die Keep-Alive-Direktive, die Ihrer Laufzeit zugeordnet ist. Ein Beispiel finden Sie unter Wiederverwenden von Verbindungen mit Keep-Alive in Node.js.

  • Verwenden Sie Umgebungsvariablen um Betriebsparameter an Ihre Funktion zu übergeben. Wenn Sie z. B. Daten in einen Amazon-S3-Bucket schreiben, anstatt den Bucket-Namen, in den Sie schreiben, hartzucodieren, konfigurieren Sie den Bucket-Namen als Umgebungsvariable.

  • Vermeiden Sie rekursive Aufrufe in Ihrer Lambda-Funktion, bei denen sich die Funktion selbst aufruft oder einen Prozess initiiert, der die Funktion möglicherweise erneut aufruft. Dies kann zu unvorhergesehenen Mengen an Funktionsaufrufen führen und höhere Kosten zur Folge haben. Wenn Sie eine unbeabsichtigte Anzahl von Aufrufen sehen, setzen Sie die für die Funktion reservierte Parallelität auf 0 sofort, um alle Aufrufe der Funktion zu drosseln, während Sie den Code aktualisieren.

  • Verwenden Sie APIs in Ihrem Lambda-Funktionscode nicht undokumentiert, nicht öffentlich. Für AWS Lambda verwaltete Laufzeiten führt Lambda regelmäßig Sicherheits- und Funktionsupdates für interne Lambda-Laufzeiten durch. APIs Diese internen API Updates können abwärtsinkompatibel sein, was zu unbeabsichtigten Folgen wie Aufruffehlern führen kann, wenn Ihre Funktion von diesen nicht öffentlichen Daten abhängig ist. APIs Eine Liste der öffentlich verfügbaren Dateien finden Sie in der API Referenz. APIs

  • Schreiben Sie idempotenten Code. Das Schreiben idempotenter Code für Ihre Funktionen stellt sicher, dass doppelte Ereignisse auf die gleiche Weise behandelt werden. Ihr Code sollte Ereignisse ordnungsgemäß validieren und doppelte Ereignisse ordnungsgemäß behandeln. Weitere Informationen finden Sie unter Wie mache ich meine Lambda-Funktion idempotent?.