Search code examples
c#amazon-web-servicesaws-lambdaaws-sdk-net

C# Lambda annotations in AWS Gateway fail to upload a binary PDF file to S3 bucket


I created a C# AWS lambda app that simply uploads a PDF binary file using the Amazon.Lambda.Annotations package.

[LambdaFunction(Policies = "AWSLambdaBasicExecutionRole", MemorySize = 1024, Timeout = 5)]
[RestApi(LambdaHttpMethod.Post, "/")]
public async Task<IHttpResult> Post(
  [FromBody] byte[] fileContent, // binary upload
  [FromQuery] string fileName,
  ILambdaContext context)
{
  // lambda code
}

This approach, however, returns a 500 and there is nothing in the logs to indicate what the issue was.

I tried simply switching the fileContent to a string, even though in C# strings are never meant for binary format.

[LambdaFunction(Policies = "AWSLambdaBasicExecutionRole", MemorySize = 1024, Timeout = 5)]
[RestApi(LambdaHttpMethod.Post, "/")]
public async Task<IHttpResult> Post(
  [FromBody] string fileContent, // binary as raw weird string
  [FromQuery] string fileName,
  ILambdaContext context)
{
  await _s3Client.PutObjectAsync(new PutObjectRequest
  {
    BucketName = S3BucketName,
    Key = fileName,
    ContentBody = fileContent
  });

  return HttpResults.Created();
}

This approach actually silently fails because the S3 file is not an actual PDF file but some weird non-binary representation.

How can I upload a PDF file in binary format using C#, and lambda annotations?


Solution

  • I believe the answer to your question is to assume the raw string is a base64 string.

    [LambdaFunction(Policies = "AWSLambdaBasicExecutionRole", MemorySize = 1024, Timeout = 5)]
    [RestApi(LambdaHttpMethod.Post, "/")]
    public async Task<IHttpResult> Post(
      [FromBody] string fileContent, // assume base64 because it has to be
      [FromQuery] string fileName,
      ILambdaContext context)
    {
      var byteArray = Convert.FromBase64String(fileContent);
      using var inputStream = new MemoryStream(byteArray); // turn into binary format
    
      await _s3Client.PutObjectAsync(new PutObjectRequest
      {
        BucketName = S3BucketName,
        Key = fileName,
        InputStream = inputStream // upload proper binary file
      });
    
      return HttpResults.Created();
    }
    

    Then, you turn the raw string into an InputStream so S3 knows to upload this as in binary format.

    You may get a 502 Bad Gateway error because the raw string is not in base64. To solve this, simply add "application/pdf" in the AWS Gateway settings to indicate this should be converted to the right raw string.

    AWS Gateway API Config