Definisci il gestore di funzioni Lambda in C# - AWS Lambda

Le traduzioni sono generate tramite traduzione automatica. In caso di conflitto tra il contenuto di una traduzione e la versione originale in Inglese, quest'ultima prevarrà.

Definisci il gestore di funzioni Lambda in C#

Il gestore di funzioni Lambda è il metodo nel codice della funzione che elabora gli eventi. Quando viene richiamata la funzione, Lambda esegue il metodo del gestore. La funzione viene eseguita fino a quando il gestore non restituisce una risposta, termina o scade.

Quando la funzione viene richiamata e Lambda esegue il metodo del gestore della funzione, passa due argomenti alla funzione. Il primo argomento è l'oggetto event. Quando un altro Servizio AWS richiama la funzione, l'eventoggetto contiene dati sull'evento che ha causato l'invocazione della funzione. Ad esempio, un event oggetto di API Gateway contiene informazioni sul percorso, sul HTTP metodo e sulle intestazioni. HTTP L'esatta struttura degli eventi varia in base alla funzione che Servizio AWS richiama la funzione. Per ulteriori informazioni sui formati degli eventi per i singoli servizi, consulta Richiamare Lambda con eventi di altri servizi AWS.

Lambda passa alla funzione anche un oggetto context. Questo oggetto di contesto contiene informazioni sull'invocazione, sulla funzione e sull'ambiente di esecuzione. Per ulteriori informazioni, consulta Utilizzo dell'oggetto contesto Lambda per recuperare informazioni sulla funzione C#.

Il formato nativo per tutti gli eventi Lambda è costituito da flussi di byte che rappresentano l'evento formattato. JSON Se i parametri di input e output della funzione non sono di tipo System.IO.Stream, è necessario serializzarli. Specifica il serializzatore che desideri utilizzare impostando l'attributo assembly LambdaSerializer. Per ulteriori informazioni, consulta Serializzazione nelle funzioni Lambda.

. NETmodelli di esecuzione per Lambda

Esistono due diversi modelli di esecuzione per l'esecuzione delle funzioni Lambda. NET: l'approccio alla libreria di classi e l'approccio all'assemblaggio eseguibile.

Nell'approccio alla libreria di classi, fornisci a Lambda una stringa che indica AssemblyName, ClassName e Method della funzione da richiamare. Per ulteriori informazioni sul formato di questa stringa, consulta Gestori di librerie di classi. Durante la fase di inizializzazione della funzione, la classe della funzione viene inizializzata e viene eseguito qualsiasi codice nel costruttore.

Nell'approccio di assembly eseguibile, si utilizza la funzionalità delle istruzioni di livello superiore di 9 C#. Questo approccio genera un assembly eseguibile che Lambda esegue ogni volta che riceve un comando invoke per la tua funzione. Fornisci a Lambda solo il nome dell'assembly eseguibile da eseguire.

Le sezioni seguenti forniscono esempi di codice di funzione per questi due approcci.

Gestori di librerie di classi

Il seguente codice di funzione Lambda mostra un esempio di metodo handler (FunctionHandler) per una funzione Lambda che utilizza l'approccio della libreria di classi. In questo esempio funtion, Lambda riceve un evento API da Gateway che richiama la funzione. La funzione legge un record da un database e restituisce il record come parte della risposta Gateway. API

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

Quando crei una funzione Lambda, devi fornire a Lambda informazioni sul gestore della funzione sotto forma di stringa del gestore. Questo indica a Lambda quale metodo del codice eseguire quando la funzione viene richiamata. In C#, il formato della stringa del gestore quando si utilizza l'approccio della libreria di classi è il seguente:

ASSEMBLY::TYPE::METHOD, dove:

  • ASSEMBLYè il nome di. NETfile di assemblaggio per l'applicazione. Se si utilizza il Amazon.Lambda.Tools CLI per creare l'applicazione e non si imposta il nome dell'assembly utilizzando la AssemblyName proprietà nel file.csproj, si ASSEMBLY tratta semplicemente del nome del file .csproj.

  • TYPE è il nome completo del tipo di gestore, costituito da Namespace e ClassName.

  • METHOD è il nome del metodo del gestore della funzione nel codice.

Per il codice di esempio mostrato, se l'assembly è denominato GetProductHandler, la stringa del gestore sarebbe GetProductHandler::GetProductHandler.Function::FunctionHandler.

Gestori di assembly eseguibili

Nell'esempio seguente, la funzione Lambda è definita come un assembly eseguibile. Il metodo handler in questo codice è denominato Handler. Quando si utilizzano assembly eseguibili, è necessario avviare il runtime Lambda. Per far ciò, viene utilizzato il metodo LambdaBootstrapBuilder.Create. Questo metodo accetta come input il metodo utilizzato dalla funzione come gestore e il serializzatore Lambda da utilizzare.

Per ulteriori informazioni sull'utilizzo delle istruzioni di primo livello, vedere Introduzione al. NET6 runtime per AWS Lambda sul blog di AWS calcolo.

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

Quando si utilizzano assembly eseguibili, la stringa del gestore che indica a Lambda come eseguire il codice è il nome dell'assembly. In questo esempio, sarebbe GetProductHandler.

Serializzazione nelle funzioni Lambda

Se la funzione Lambda utilizza i tipi di input/output diversi da un oggetto Stream, è necessario aggiungere una libreria di serializzazione all'applicazione. È possibile implementare la serializzazione utilizzando la serializzazione standard basata sulla riflessione fornita da System.Text.Json e Newtonsoft.Json oppure utilizzando la serializzazione generata dal codice sorgente.

Utilizzo della serializzazione generata dal codice sorgente

La serializzazione generata dal codice sorgente è una funzionalità di. NETversioni 6 e successive che consentono la generazione del codice di serializzazione in fase di compilazione. Elimina la necessità di riflessione e può migliorare le prestazioni della tua funzione. Per utilizzare la serializzazione generata dal codice sorgente nella tua funzione, procedi come segue:

  • Crea una nuova classe parziale che eredita da JsonSerializerContext, aggiungendo attributi JsonSerializable per tutti i tipi che richiedono la serializzazione o la deserializzazione.

  • Configura il LambdaSerializer per utilizzare un SourceGeneratorLambdaJsonSerializer<T>.

  • Aggiorna qualsiasi serializzazione o deserializzazione manuale nel codice dell'applicazione per utilizzare la classe appena creata.

Nel codice seguente viene illustrata una funzione di esempio che utilizza la serializzazione generata dal codice sorgente.

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

Se desideri utilizzare la compilazione anticipata nativa (AOT) con Lambda, devi utilizzare la serializzazione generata dal codice sorgente.

Utilizzo della serializzazione basata sulla riflessione

AWS fornisce librerie predefinite che consentono di aggiungere rapidamente la serializzazione all'applicazione. È possibile configurarlo utilizzando i pacchetti Amazon.Lambda.Serialization.SystemTextJson o Amazon.Lambda.Serialization.Json NuGet . Dietro le quinte, Amazon.Lambda.Serialization.SystemTextJson utilizza System.Text.Json per eseguire attività di serializzazione e Amazon.Lambda.Serialization.Json utilizza il pacchetto Newtonsoft.Json.

È possibile inoltre creare una libreria di serializzazione personalizzata implementando l'interfaccia ILambdaSerializer, disponibile come parte della libreria Amazon.Lambda.Core. L'interfaccia definisce due metodi:

  • T Deserialize<T>(Stream requestStream);

    Implementate questo metodo per deserializzare il payload della richiesta dall'InvokeAPIinterno all'oggetto che viene passato al gestore della funzione Lambda.

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

    Implementate questo metodo per serializzare il risultato restituito dal gestore della funzione Lambda nel payload di risposta restituito dall'operazione. Invoke API

Semplificazione del codice delle funzioni con il framework Lambda Annotations

Lambda Annotations è un framework per. NET6 e. NET8 che semplifica la scrittura di funzioni Lambda usando C#. Con il framework Annotations, è possibile sostituire gran parte del codice in una funzione Lambda scritta utilizzando il normale modello di programmazione. Il codice scritto utilizzando il framework utilizza espressioni più semplici che consentono di concentrarsi sulla logica aziendale.

Il codice di esempio riportato di seguito mostra come l'utilizzo del framework delle annotazioni può semplificare la scrittura di funzioni Lambda. Il primo esempio mostra il codice scritto utilizzando il normale modello di programmazione Lambda e il secondo mostra l'equivalente utilizzando il framework 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; }

Per un altro esempio di come l'utilizzo di Lambda Annotations può semplificare il codice, consulta questo esempio di applicazione cross-service nel repository. awsdocs/aws-doc-sdk-examples GitHub La cartella PamApiAnnotations utilizza Lambda Annotations nel file function.cs principale. Per fare un confronto, la cartella PamApi contiene file equivalenti scritti utilizzando il normale modello di programmazione Lambda.

Il framework Annotations utilizza generatori di codice sorgente per generare codice che si traduce dal modello di programmazione Lambda al codice visto nel secondo esempio.

Per ulteriori informazioni su come utilizzare Lambda Annotations for. NET, consulta le seguenti risorse:

Iniezione delle dipendenze con il framework Lambda Annotations

Puoi utilizzare il framework Lambda Annotations anche per aggiungere l'iniezione di dipendenze alle tue funzioni Lambda utilizzando una sintassi che conosci. Quando aggiungi un attributo [LambdaStartup] a un file Startup.cs, il framework Lambda Annotations genererà il codice richiesto in fase di compilazione.

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

La tua funzione Lambda può iniettare servizi utilizzando l'iniezione del costruttore o iniettandoli in metodi individuali utilizzando l'attributo [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); } }

Restrizioni del gestore della funzione Lambda

Tieni in considerazione che la firma del gestore presenta alcune restrizioni.

  • Nella firma del gestore non è possibile utilizzare unsafe e tipi di puntatori. Tuttavia, il contesto unsafe può essere utilizzato nel metodo del gestore e nelle relative dipendenze. Per ulteriori informazioni, consulta unsafe (Riferimenti per C#) sul sito web Microsoft Docs.

  • Non può passare un numero variabile di parametri utilizzando la parola chiave params o utilizzare ArgIterator come parametro di input o di restituzione per supportare un numero variabile di parametri.

  • Il gestore potrebbe non essere un metodo generico, ad esempio IList <T>Sort <T>(IList<T>input).

  • I gestori asincroni con firma async void non sono supportati.

Procedure consigliate per le funzioni Lambda in C#

Segui le linee guida riportate nell'elenco seguente per utilizzare le migliori pratiche di codifica durante la creazione delle funzioni Lambda:

  • Separare il gestore Lambda dalla logica principale. In questo modo è possibile creare una funzione di cui è più semplice eseguire l'unit test.

  • Controllare le dipendenze nel pacchetto di distribuzione della funzione. L'ambiente di AWS Lambda esecuzione contiene diverse librerie. Per abilitare il set di caratteristiche e aggiornamenti della sicurezza più recenti, Lambda aggiorna periodicamente tali librerie. Tali aggiornamenti possono introdurre lievi modifiche al comportamento della funzione Lambda. Per mantenere il controllo completo delle dipendenze utilizzate dalla funzione, inserire tutte le dipendenze nel pacchetto di implementazione.

  • Ridurre la complessità delle dipendenze. Preferire framework più semplici che si caricano velocemente all'avvio del contesto di esecuzione.

  • Ridurre al minimo le dimensioni del pacchetto di implementazione al fine di soddisfare le esigenze di runtime. In questo modo viene ridotta la quantità di tempo necessaria per il download del pacchetto e per la relativa decompressione prima dell'invocazione. Per le funzioni create in. NET, evita di caricare l'intera AWS SDK libreria come parte del pacchetto di distribuzione. Dipendi invece in modo selettivo dai moduli che raccolgono i componenti di cui SDK hai bisogno (ad esempio DynamoDB, moduli Amazon SDK S3 e librerie di base Lambda).

  • Sfruttare il riutilizzo del contesto di esecuzione per migliorare le prestazioni della funzione. Inizializza SDK i client e le connessioni al database all'esterno del gestore delle funzioni e memorizza nella cache gli asset statici localmente nella directory. /tmp Le chiamate successive elaborate dalla stessa istanza della funzione possono riutilizzare queste risorse. Ciò consente di risparmiare sui costi riducendo i tempi di esecuzione delle funzioni.

    Per evitare potenziali perdite di dati tra le chiamate, non utilizzare il contesto di esecuzione per archiviare dati utente, eventi o altre informazioni con implicazioni di sicurezza. Se la funzione si basa su uno stato mutabile che non può essere archiviato in memoria all'interno del gestore, considerare la possibilità di creare una funzione separata o versioni separate di una funzione per ogni utente.

  • Utilizzare una direttiva keep-alive per mantenere le connessioni persistenti. Lambda elimina le connessioni inattive nel tempo. Se si tenta di riutilizzare una connessione inattiva quando si richiama una funzione, si verificherà un errore di connessione. Per mantenere la connessione persistente, utilizzare la direttiva keep-alive associata al runtime. Per un esempio, vedere Riutilizzo delle connessioni con Keep-Alive in Node.js.

  • Utilizzare le variabili di ambiente per passare i parametri operativi alla funzione. Se ad esempio si scrive in un bucket Amazon S3 anziché impostare come hard-coded il nome del bucket in cui si esegue la scrittura, configurare tale nome come una variabile di ambiente.

  • Evita di usare invocazioni ricorsive nella tua funzione Lambda, in cui la funzione si richiama da sola o avvia un processo che potrebbe richiamare nuovamente la funzione. Ciò potrebbe provocare un volume non desiderato di invocazioni della funzione e un aumento dei costi. Se vedi un volume involontario di chiamate, imposta la concorrenza riservata alla funzione su «0immediate» per limitare tutte le chiamate alla funzione mentre aggiorni il codice.

  • Non utilizzare documenti non documentati e non pubblici APIs nel codice della funzione Lambda. Per i runtime AWS Lambda gestiti, Lambda applica periodicamente aggiornamenti di sicurezza e funzionalità all'interno di Lambda. APIs Questi API aggiornamenti interni possono essere incompatibili con le versioni precedenti e portare a conseguenze indesiderate, come errori di chiamata se la funzione dipende da questi aggiornamenti non pubblici. APIs Vedi il riferimento per un elenco di quelli disponibili al pubblico. API APIs

  • Scrivi un codice idempotente. La scrittura di un codice idempotente per le tue funzioni garantisce che gli eventi duplicati vengano gestiti allo stesso modo. Il tuo codice dovrebbe convalidare correttamente gli eventi e gestire con garbo gli eventi duplicati. Per ulteriori informazioni, consulta Come posso rendere idempotente la mia funzione Lambda?.