Gestionnaire de fonctions Lambda dans C# - AWS Lambda

Les traductions sont fournies par des outils de traduction automatique. En cas de conflit entre le contenu d'une traduction et celui de la version originale en anglais, la version anglaise prévaudra.

Gestionnaire de fonctions Lambda dans C#

Le gestionnaire de fonction Lambda est la méthode dans votre code de fonction qui traite les événements. Lorsque votre fonction est invoquée, Lambda exécute la méthode du gestionnaire. Votre fonction s’exécute jusqu’à ce que le gestionnaire renvoie une réponse, se ferme ou expire.

Lorsque votre fonction est invoquée et que Lambda exécute la méthode du gestionnaire de votre fonction, celle-ci transmet deux arguments à votre fonction. Le premier argument est l'objet event. Lorsqu'une autre Service AWS personne appelle votre fonction, l'eventobjet contient des données relatives à l'événement à l'origine de l'appel de votre fonction. Par exemple, un objet event provenant d'API Gateway contient des informations sur le chemin d'accès, la méthode HTTP et les en-têtes HTTP. La structure exacte de l'événement varie en fonction de l' Service AWS appel de votre fonction. Consultez Utilisation AWS Lambda avec d'autres services pour obtenir pour en savoir plus sur les formats d'événements des différents services.

Lambda transmet également un objet de context à votre fonction. Cet objet contient des informations sur l'invocation, la fonction et l'environnement d'exécution. Pour de plus amples informations, veuillez consulter AWS LambdaObjet de contexte en C#.

Le format natif de tous les événements Lambda est constitué de flux d'octets représentant l'événement formaté au format JSON. À moins que les paramètres d'entrée et de sortie de votre fonction ne soient de typeSystem.IO.Stream, vous devez les sérialiser. Spécifiez le sérialiseur que vous souhaitez utiliser en définissant l'attribut d'assemblage LambdaSerializer. Pour de plus amples informations, veuillez consulter Sérialisation dans les fonctions Lambda.

Modèles d'exécution .NET pour Lambda

Il existe deux modèles d'exécution différents pour les fonctions Lambda dans .NET : l'approche de la bibliothèque de classes et l'approche de l'assemblage exécutable.

Dans l'approche de la bibliothèque de classes, vous fournissez à Lambda une chaîne indiquant le AssemblyName, ClassName, et Method de la fonction à invoquer. Pour en savoir plus sur le format de cette chaîne, consultez Gestionnaires de bibliothèques de classes. Pendant la phase d'initialisation de la fonction, la classe de votre fonction est initialisée et tout code contenu dans le constructeur est exécuté.

Dans l'approche de l'assemblage exécutable, vous utilisez la fonctionnalité des instructions de premier niveau de C# 9. Cette approche génère un assemblage exécutable que Lambda exécute chaque fois qu'il reçoit une commande d'invocation pour votre fonction. Vous ne fournissez à Lambda que le nom de l'assemblage exécutable à exécuter.

Les sections suivantes donnent des exemples de code de fonction pour ces deux approches.

Gestionnaires de bibliothèques de classes

Le code de la fonction Lambda suivant montre un exemple d'une méthode du gestionnaire (FunctionHandler) pour une fonction Lambda qui utilise l'approche de la bibliothèque de classe. Dans cet exemple de fonction, Lambda reçoit un événement provenant d’API Gateway qui invoque la fonction. La fonction lit un enregistrement à partir d'une base de données et renvoie l'enregistrement dans le cadre de la réponse de l'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) }; } }

Lorsque vous créez une fonction Lambda, vous devez fournir à Lambda des informations sur le gestionnaire de votre fonction sous la forme d'une chaîne de gestionnaire. Cette chaîne indique à Lambda quelle méthode de votre code doit être exécutée lorsque votre fonction est invoquée. En C#, lorsque l'on utilise l'approche de la bibliothèque de classes, le format de la chaîne du gestionnaire est le suivant :

ASSEMBLY::TYPE::METHOD, où :

  • ASSEMBLY est le nom du fichier d'assemblage .NET de votre application. Si vous utilisez la CLI Amazon.Lambda.Tools pour créer votre application et que vous ne définissez pas le nom de l'assemblage à l'aide de la propriété AssemblyName dans le fichier .csproj, alors ASSEMBLY est simplement le nom de votre fichier .csproj.

  • TYPE est le nom complet du type de gestionnaire, composé de Namespace et de ClassName.

  • METHOD est le nom de la méthode du gestionnaire de fonction dans votre code.

Dans l'exemple de code illustré, si l'assemblage est nommé GetProductHandler, alors la chaîne du gestionnaire sera GetProductHandler::GetProductHandler.Function::FunctionHandler.

Gestionnaires d'assemblages exécutables

Dans l'exemple suivant, la fonction Lambda est définie comme un assemblage exécutable. La méthode du gestionnaire dans ce code est nommée Handler. Lors de l'utilisation d'assemblages exécutables, l'exécution Lambda doit être amorcée. Pour ce faire, vous devez utiliser la méthode LambdaBootstrapBuilder.Create. Cette méthode prend comme entrée la méthode que votre fonction utilise en tant que gestionnaire et le sérialiseur Lambda à utiliser.

Pour plus d'informations sur l'utilisation des instructions de haut niveau, consultez la section Présentation de l'environnement d'exécution .NET 6 AWS Lambda sur le blog de AWS calcul.

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

Lors de l'utilisation d'assemblages exécutables, la chaîne du gestionnaire qui indique à Lambda comment exécuter votre code est le nom de l'assemblage. Dans cet exemple, ce serait GetProductHandler.

Sérialisation dans les fonctions Lambda

Si votre fonction Lambda utilise des types d'entrée ou de sortie autres qu'un objet Stream, vous devez ajouter une bibliothèque de sérialisation à votre application. Vous pouvez mettre en œuvre la sérialisation en utilisant la sérialisation standard basée sur la réflexion fournie par System.Text.Json et Newtonsoft.Json, ou en utilisant la sérialisation générée par la source.

Utilisation de la sérialisation générée par la source

La sérialisation générée par la source est une fonctionnalité des versions .NET 6 et ultérieures qui permet de générer du code de sérialisation au moment de la compilation. Elle supprime le besoin de réflexion et peut améliorer les performances de votre fonction. Pour utiliser la sérialisation générée par la source dans votre fonction, procédez comme suit :

  • Créez une nouvelle classe partielle qui hérite de JsonSerializerContext, en ajoutant des attributs JsonSerializable pour tous les types qui nécessitent une sérialisation ou une désérialisation.

  • Configurez le LambdaSerializer afin d'utiliser un SourceGeneratorLambdaJsonSerializer<T>.

  • Mettez à jour toute sérialisation ou désérialisation manuelle dans le code de votre application afin d'utiliser la classe nouvellement créée.

Un exemple de fonction utilisant la sérialisation générée par la source est présenté dans le code suivant.

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

Si vous souhaitez utiliser la compilation native anticipée (AOT) avec Lambda, vous devez utiliser la sérialisation générée à la source.

Utilisation de la sérialisation basée sur la réflexion

AWS fournit des bibliothèques prédéfinies pour vous permettre d'ajouter rapidement une sérialisation à votre application. Vous pouvez le configurer à l'aide des Amazon.Lambda.Serialization.Json NuGet packages Amazon.Lambda.Serialization.SystemTextJson ou. En arrière-plan, Amazon.Lambda.Serialization.SystemTextJson utilise System.Text.Json pour effectuer des tâches de sérialisation, et Amazon.Lambda.Serialization.Json utilise le package Newtonsoft.Json.

Vous pouvez également créer votre propre bibliothèque de sérialisation en implémentant l'interface ILambdaSerializer, disponible dans la bibliothèque Amazon.Lambda.Core. Cette interface définit deux méthodes :

  • T Deserialize<T>(Stream requestStream);

    Vous implémentez cette méthode afin de désérialiser la charge utile de la demande à partir de l'API Invoke dans l'objet qui est transféré à votre gestionnaire de fonction Lambda.

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

    Vous implémentez cette méthode pour sérialiser le résultat renvoyé à partir de votre gestionnaire de fonction Lambda dans la charge utile de la réponse renvoyée par l'opération d'API Invoke.

Simplifiez le code de la fonction à l'aide du cadre d'annotations Lambda

Lambda Annotations est un framework pour .NET 6 et .NET 8 qui simplifie l'écriture de fonctions Lambda en C#. Grâce au cadre d'annotations, vous pouvez remplacer une grande partie du code d'une fonction Lambda écrite à l'aide du modèle de programmation habituel. Le code écrit à l'aide du cadre utilise des expressions plus simples qui vous permettent de vous concentrer sur votre logique commerciale.

L'exemple de code suivant montre comment l'utilisation du cadre d'annotations peut simplifier l'écriture des fonctions Lambda. Le premier exemple montre le code écrit à l'aide du modèle de programme Lambda habituel, et le second montre l'équivalent à l'aide du cadre d'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; }

Pour un autre exemple de la façon dont l'utilisation des annotations Lambda peut simplifier votre code, consultez cet exemple d'application multiservice dans le référentiel. awsdocs/aws-doc-sdk-examples GitHub Le dossier PamApiAnnotations utilise des annotations Lambda dans le fichier principal function.cs. À titre de comparaison, le dossier PamApi contient des fichiers équivalents écrits à l'aide du modèle de programmation Lambda habituel.

Le cadre d'annotations utilise des générateurs de source pour générer un code qui traduit le modèle de programmation Lambda en code tel qu'il apparaît dans le deuxième exemple.

Pour en savoir plus sur l'utilisation des annotations Lambda pour .NET, consultez les ressources suivantes :

Injection de dépendances grâce au cadre d'annotations Lambda

Vous pouvez également utiliser le cadre d'annotations Lambda pour ajouter l'injection de dépendance à vos fonctions Lambda en utilisant une syntaxe que vous connaissez bien. Lorsque vous ajoutez un attribut [LambdaStartup] à un fichier Startup.cs, le cadre d'annotations Lambda génère le code nécessaire au moment de la compilation.

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

Votre fonction Lambda peut injecter des services en utilisant l'injection de constructeur ou en injectant dans des méthodes individuelles à l'aide de l'attribut [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); } }

Restrictions liées au gestionnaire de fonctions Lambda

Notez que des restrictions s'appliquent à la signature du gestionnaire.

  • Il peut ne pas s'agir du unsafe et utiliser des types de pointeur dans la signature du gestionnaire, bien que le contexte unsafe puisse être utilisé dans la méthode de gestionnaire et ses dépendances. Pour de plus amples informations, veuillez consulterdangereux (référence C#)sur le site Web Microsoft Docs.

  • Il peut ne pas transférer un certain nombre de paramètres à l'aide du mot clé params ou utiliser ArgIterator comme paramètre d'entrée ou de retour, pour prendre en charge un nombre de paramètres variable.

  • Le gestionnaire peut ne pas être une méthode générique, par exemple, IList<T> Sort<T>(IList<T> input).

  • Les gestionnaires asynchrones avec une signature async void ne sont pas pris en charge.