Définir le gestionnaire de fonctions Lambda en 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.

Définir le gestionnaire de fonctions Lambda en 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 event objet de API Gateway contient des informations sur le chemin, la HTTP méthode et HTTP les en-têtes. La structure exacte de l'événement varie en fonction de l' Service AWS appel de votre fonction. Consultez Invoquer Lambda avec des événements provenant d'autres services AWS 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 Utilisation de l'objet de contexte Lambda pour récupérer les informations de la fonction C#.

Le format natif pour tous les événements Lambda est constitué de flux d'octets représentant l'événement JSON formaté. À 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.

. NETmodèles d'exécution pour Lambda

Il existe deux modèles d'exécution différents pour exécuter 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 API de Gateway qui appelle la fonction. La fonction lit un enregistrement dans une base de données et le renvoie dans le cadre de la réponse de la API passerelle.

[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ù :

  • ASSEMBLYest le nom du. NETfichier d'assemblage pour votre application. Si vous utilisez le Amazon.Lambda.Tools CLI pour créer votre application et que vous ne définissez pas le nom de l'assembly à l'aide de la AssemblyName propriété du fichier .csproj, il ASSEMBLY s'agit simplement du 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, voir Présentation du. NET6 runtime pour AWS Lambda on the 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) }; };

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é de. NETversions 6 et ultérieures qui permettent 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 par 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 pour désérialiser la charge utile de la demande depuis l'InvokeAPIobjet transmis à votre gestionnaire de fonctions Lambda.

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

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

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

Lambda Annotations est un framework pour. NET6 et. NET8 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 plus d'informations 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 n'est peut-être pas 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.

Meilleures pratiques en matière de code pour les fonctions Lambda C#

Respectez les directives de la liste suivante pour utiliser les meilleures pratiques de codage lors de la création de vos fonctions Lambda :

  • Séparez le gestionnaire Lambda de votre logique principale. Cela vous permet de créer une fonction testable plus unitaire.

  • Contrôlez les dépendances du package de déploiement de vos fonctions. L'environnement AWS Lambda d'exécution contient un certain nombre de bibliothèques. Pour activer le dernier ensemble de mises à jour des fonctionnalités et de la sécurité, Lambda met régulièrement à jour ces bibliothèques. Ces mises à jour peuvent introduire de subtiles modifications dans le comportement de votre fonction Lambda. Pour disposer du contrôle total des dépendances que votre fonction utilise, empaquetez toutes vos dépendances avec votre package de déploiement.

  • Réduisez la complexité de vos dépendances. Privilégiez les infrastructures plus simples qui se chargent rapidement au démarrage de l’environnement d’exécution.

  • Réduisez la taille de votre package de déploiement selon ses besoins d’exécution. Cela contribue à réduire le temps nécessaire au téléchargement et à la décompression de votre package de déploiement avant l’invocation. Pour les fonctions créées dans. NET, évitez de télécharger l'intégralité de la AWS SDK bibliothèque dans le cadre de votre package de déploiement. Dépendez plutôt de manière sélective des modules qui récupèrent les composants dont SDK vous avez besoin (par exemple DynamoDB, les SDK modules Amazon S3 et les bibliothèques principales Lambda).

  • Tirez parti de la réutilisation de l’environnement d’exécution pour améliorer les performances de votre fonction. Initialisez les SDK clients et les connexions à la base de données en dehors du gestionnaire de fonctions et mettez en cache les actifs statiques localement dans le /tmp répertoire. Les invocations ultérieures traitées par la même instance de votre fonction peuvent réutiliser ces ressources. Cela permet d’économiser des coûts, tout en réduisant le temps d’exécution de la fonction.

    Pour éviter des éventuelles fuites de données entre les invocations, n’utilisez pas l’environnement d’exécution pour stocker des données utilisateur, des événements ou d’autres informations ayant un impact sur la sécurité. Si votre fonction repose sur un état réversible qui ne peut pas être stocké en mémoire dans le gestionnaire, envisagez de créer une fonction distincte ou des versions distinctes d’une fonction pour chaque utilisateur.

  • Utilisez une directive keep-alive pour maintenir les connexions persistantes. Lambda purge les connexions inactives au fil du temps. Si vous tentez de réutiliser une connexion inactive lorsque vous invoquez une fonction, cela entraîne une erreur de connexion. Pour maintenir votre connexion persistante, utilisez la directive Keep-alive associée à votre environnement d’exécution. Pour obtenir un exemple, consultez Réutilisation des connexions avec Keep-Alive dans Node.js.

  • Utilisez des variables d’environnement pour transmettre des paramètres opérationnels à votre fonction. Par exemple, si vous écrivez dans un compartiment Amazon S3 au lieu de coder en dur le nom du compartiment dans lequel vous écrivez, configurez le nom du compartiment comme variable d’environnement.

  • Évitez d'utiliser des invocations récursives dans votre fonction Lambda, lorsque la fonction s'invoque elle-même ou initie un processus susceptible de l'invoquer à nouveau. Cela peut entraîner un volume involontaire d’invocations de fonction et des coûts accrus. Si vous constatez un volume d'invocations involontaire, réglez la fonction réservée à la simultanéité sur 0 immédiatement afin de limiter toutes les invocations à la fonction pendant que vous mettez à jour le code.

  • N'utilisez pas de code non documenté ni public APIs dans votre code de fonction Lambda. Pour les AWS Lambda environnements d'exécution gérés, Lambda applique régulièrement des mises à jour de sécurité et fonctionnelles aux applications internes de Lambda. APIs Ces API mises à jour internes peuvent être rétroincompatibles, ce qui peut entraîner des conséquences imprévues, telles que des échecs d'invocation si votre fonction dépend de ces mises à jour non publiques. APIs Voir la API référence pour une liste des documents accessibles au publicAPIs.

  • Écriture du code idempotent. L’écriture de code idempotent pour vos fonctions garantit ne gestion identique des événements dupliqués. Votre code doit valider correctement les événements et gérer correctement les événements dupliqués. Pour de plus amples informations, veuillez consulterComment faire en sorte que ma fonction Lambda soit idempotente ?.