C#으로 작성한 Lambda 함수 핸들러 - AWS Lambda

기계 번역으로 제공되는 번역입니다. 제공된 번역과 원본 영어의 내용이 상충하는 경우에는 영어 버전이 우선합니다.

C#으로 작성한 Lambda 함수 핸들러

Lambda 함수의 핸들러는 이벤트를 처리하는 함수 코드의 메서드입니다. 함수가 호출되면 Lambda는 핸들러 메서드를 실행합니다. 함수는 핸들러가 응답을 반환하거나 종료하거나 제한 시간이 초과될 때까지 실행됩니다.

함수가 간접적으로 호출되고 Lambda가 함수의 핸들러 메서드를 실행하면 함수에 두 인수를 전달합니다. 첫 번째 인수는 event 객체입니다. 다른 AWS 서비스이(가) 함수를 간접적으로 호출하면 event 객체에는 함수 간접 호출을 유발한 이벤트에 대한 데이터가 포함됩니다. 예를 들어 API Gateway의 event 객체에는 경로, HTTP 메서드, HTTP 헤더에 대한 정보가 포함되어 있습니다. 정확한 이벤트 구조는 AWS 서비스 함수 간접 호출에 따라 달라집니다. 개별 서비스의 이벤트 형식에 대한 자세한 내용은 다른 서비스와 함께 AWS Lambda 사용을(를) 참조하십시오.

또한 Lambda는 context 객체를 함수에 전달합니다. 이 객체에는 호출, 함수 및 실행 환경에 대한 정보가 포함되어 있습니다. 자세한 내용은 AWS Lambda 컨텍스트 객체(C#) 단원을 참조하십시오.

모든 Lambda 이벤트의 기본 형식은 JSON 형식의 이벤트를 나타내는 바이트 스트림입니다. 함수 입력 및 출력 파라미터는 System.IO.Stream 유형인 경우를 제외하고 직렬화해야 합니다. LambdaSerializer 어셈블리 속성을 설정하여 사용하려는 시리얼라이저를 지정하십시오. 자세한 내용은 Lambda 함수의 직렬화 단원을 참조하십시오.

람다용 .NET 실행 모델

.NET에서 Lambda 함수를 실행하기 위한 두 가지 실행 모델, 즉 클래스 라이브러리 접근 방식과 실행 가능한 어셈블리 접근 방식이 있습니다.

클래스 라이브러리 접근 방식에서는 간접적으로 호출할 함수의 AssemblyName, ClassNameMethod을(를) 나타내는 문자열이 있는 Lambda를 제공합니다. 이 문자열의 형식에 대한 자세한 내용은 클래스 라이브러리 핸들러을(를) 참조하십시오. 함수 초기화 단계에서 함수 클래스가 초기화되고 생성자의 코드가 실행됩니다.

실행 가능한 어셈블리 접근 방식에서는 C# 9의 최상위 명령문 기능을 사용합니다. 이 접근 방식은 함수에 대한 간접 호출 명령을 수신할 때마다 Lambda가 실행하는 실행 가능한 어셈블리를 생성합니다. 실행할 실행 가능한 어셈블리의 이름만 Lambda에 제공합니다.

다음 섹션에서는 이 두 가지 접근 방식에 대한 예제 함수 코드를 제공합니다.

클래스 라이브러리 핸들러

다음 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은(는) 핸들러 유형의 전체 이름으로,NamespaceClassName(으)로 돼 있습니다.

  • METHOD은(는) 코드에 있는 함수 핸들러 메서드의 이름입니다.

표시된 예제 코드에서 어셈블리 이름이 GetProductHandler(으)로 지정되면 핸들러 문자열은 GetProductHandler::GetProductHandler.Function::FunctionHandler이(가) 됩니다.

실행 가능한 어셈블리 핸들러

다음 예제에서 Lambda 함수는 실행 가능한 어셈블리로 정의됩니다. 이 코드의 핸들러 메서드는 Handler(이)라는 이름으로 지정됩니다. 실행 가능한 어셈블리를 사용하는 경우 Lambda 런타임을 부트스트랩해야 합니다. 그렇게 하려면 LambdaBootstrapBuilder.Create 메서드를 사용합니다. 이 메서드는 함수가 핸들러로 사용하는 메서드와 사용할 Lambda 시리얼라이저를 입력으로 사용합니다.

최상위 명령문 사용에 대한 자세한 내용은 AWS compute 블로그에서.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.JsonNewtonsoft.Json에서 제공하는 표준 리플렉션 기반 직렬화를 사용하거나 소스 생성 직렬화를 사용하여 직렬화를 구현할 수 있습니다.

소스 생성 직렬화 사용

소스 생성 직렬화는 컴파일 시간에서 직렬화 코드를 생성할 수 있는 .NET 버전 6 이상의 기능입니다. 이를 통해 리플렉션이 필요하지 않으며 함수의 성능을 향상시킬 수 있습니다. 함수에서 소스 생성 직렬화를 사용하려면 다음과 같이 하십시오.

  • JsonSerializerContext에서 상속되는 새 부분 클래스를 생성하면서 직렬화 또는 역직렬화가 필요한 모든 유형에 대한 JsonSerializable 속성을 추가합니다.

  • SourceGeneratorLambdaJsonSerializer<T>을(를) 사용하여 LambdaSerializer을(를) 구성합니다.

  • 새로 생성한 클래스를 사용하도록 애플리케이션 코드의 수동 직렬화 또는 역직렬화를 업데이트하십시오.

소스 생성 직렬화를 사용하는 예제 함수는 다음 코드에 나와 있습니다.

[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 주석 프레임워크를 사용하여 함수 코드를 간소화합니다

Lambda 주석은 C#을 사용하여 Lambda 함수 작성을 간소화하는 .NET 6 및 .NET 8용 프레임워크입니다. 주석 프레임워크를 사용하면 일반 프로그래밍 모델을 사용하여 작성된 Lambda 함수의 코드 대부분을 대체할 수 있습니다. 프레임워크를 사용하여 작성된 코드는 더 간단한 식을 사용하므로 비즈니스 로직에 집중할 수 있습니다.

다음 예제 코드는 주석 프레임워크를 사용하여 Lambda 함수 작성을 간소화하는 방법을 보여줍니다. 첫 번째 예제는 일반 Lambda 프로그램 모델을 사용하여 작성된 코드를 보여주고, 두 번째 예제는 주석 프레임워크를 사용하여 동일한 코드를 보여줍니다.

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 주석을 사용합니다. PamApi 폴더에는 비교를 위해 일반 Lambda 프로그래밍 모델을 사용하여 작성된 동일한 파일이 있습니다.

주석 프레임워크는 소스 생성기를 사용하여 Lambda 프로그래밍 모델을 두 번째 예제에 표시된 코드로 변환하는 코드를 생성합니다.

NET용으로 Lambda 주석을 사용하는 방법에 대한 자세한 내용은 다음 리소스를 참조하십시오.

Lambda 주석 프레임워크를 사용한 종속성 주입

또한 Lambda 주석 프레임워크를 사용하면 익숙한 구문을 활용하여 Lambda 함수에 종속성 주입을 추가할 수 있습니다. Startup.cs 파일에 [LambdaStartup] 속성을 추가하면 Lambda 주석 프레임워크가 컴파일 타임에 필요한 코드를 생성합니다.

[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 Docs 웹 사이트에서 unsafe(C# Reference)를 참조하세요.

  • params 키워드를 사용하여 다수의 파라미터를 전달하거나 ArgIterator를 입력으로 사용하거나 다수의 파라미터를 지원하는 데 사용되는 파라미터를 반환하지 않을 수 있습니다.

  • 핸들러는 일반 메서드(예: IList<T> Sort<T>(IList<T> input))가 아닙니다.

  • 서명 async void이 있는 비동기식 핸들러는 지원되지 않습니다.