Reputation: 11
I am trying to upload an image to s3 using lambda in .NET. But facing the Timeout issue. Anyone help me with the correct lambda code.
I have used this code but it gives the timeout error. In my api-gateway I added the binary type multipart/form-data and added headers(Content-Type and Accept) too in the method request. This is the code
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Threading.Tasks;
using Amazon.Lambda.Core;
using Amazon.Lambda.APIGatewayEvents;
using Amazon.S3;
using Amazon.S3.Model;
using Microsoft.AspNetCore.WebUtilities;
using Microsoft.Net.Http.Headers;
[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))]
namespace IdCardRequest
{
public class Function
{
public async Task<APIGatewayProxyResponse> FunctionHandler(APIGatewayProxyRequest request, ILambdaContext context)
{
context.Logger.LogLine("Function started.");
try
{
// Validate request
context.Logger.LogLine("Validating request...");
if (request.HttpMethod != "POST" ||
!request.Headers.ContainsKey("Content-Type") ||
!request.Headers["Content-Type"].StartsWith("multipart/form-data"))
{
context.Logger.LogLine("Invalid request method or content type.");
return new APIGatewayProxyResponse
{
StatusCode = 400,
Body = "Invalid request method or content type"
};
}
// Get boundary from content type
context.Logger.LogLine("Getting boundary from content type...");
var boundary = GetBoundary(request.Headers["Content-Type"]);
var bodyBytes = request.IsBase64Encoded ?
Convert.FromBase64String(request.Body) :
Encoding.UTF8.GetBytes(request.Body);
using var stream = new MemoryStream(bodyBytes);
var reader = new MultipartReader(boundary, stream);
string employeeEmail = null;
string fileName = null;
string contentType = null;
byte[] fileBytes = null;
// Process multipart sections
context.Logger.LogLine("Processing multipart sections...");
MultipartSection section;
while ((section = await reader.ReadNextSectionAsync()) != null)
{
var contentDisposition = section.GetContentDispositionHeader();
if (contentDisposition.Name == "employeeEmail")
{
using var memoryStream = new MemoryStream();
await section.Body.CopyToAsync(memoryStream);
employeeEmail = Encoding.UTF8.GetString(memoryStream.ToArray());
context.Logger.LogLine($"Extracted employeeEmail: {employeeEmail}");
}
else if (contentDisposition.Name == "image" && contentDisposition.FileName != null)
{
fileName = contentDisposition.FileName.Value.Trim('"');
contentType = section.ContentType;
context.Logger.LogLine($"Extracted file name: {fileName}, Content-Type: {contentType}");
using var memoryStream = new MemoryStream();
await section.Body.CopyToAsync(memoryStream);
fileBytes = memoryStream.ToArray();
context.Logger.LogLine($"File size: {fileBytes.Length} bytes");
}
}
// Validate required fields
context.Logger.LogLine("Validating required fields...");
if (string.IsNullOrEmpty(employeeEmail) || fileBytes == null)
{
context.Logger.LogLine("Missing employeeEmail or image file.");
return new APIGatewayProxyResponse
{
StatusCode = 400,
Body = "Missing employeeEmail or image file"
};
}
// Upload to S3
context.Logger.LogLine("Uploading file to S3...");
var s3Client = new AmazonS3Client();
var bucketName = "id-card-assets";
if (string.IsNullOrEmpty(bucketName))
{
context.Logger.LogLine("BUCKET_NAME environment variable is not set.");
return new APIGatewayProxyResponse
{
StatusCode = 500,
Body = "BUCKET_NAME environment variable is not set."
};
}
var key = $"{employeeEmail}/{Guid.NewGuid()}_{fileName}";
using var fileStream = new MemoryStream(fileBytes);
var putRequest = new Amazon.S3.Model.PutObjectRequest
{
BucketName = bucketName,
Key = key,
InputStream = fileStream,
ContentType = contentType ?? "application/octet-stream"
};
context.Logger.LogLine($"Uploading to S3 bucket: {bucketName}, Key: {key}");
var response = await s3Client.PutObjectAsync(putRequest);
context.Logger.LogLine($"S3 upload response: {response.HttpStatusCode}");
if (response.HttpStatusCode == System.Net.HttpStatusCode.OK)
{
context.Logger.LogLine("File uploaded successfully.");
return new APIGatewayProxyResponse
{
StatusCode = 200,
Body = $"File uploaded successfully to: {key}",
Headers = new Dictionary<string, string> { { "Content-Type", "text/plain" } }
};
}
else
{
context.Logger.LogLine($"S3 upload failed with status code: {response.HttpStatusCode}");
return new APIGatewayProxyResponse
{
StatusCode = 500,
Body = $"S3 upload failed with status code: {response.HttpStatusCode}"
};
}
}
catch (AmazonS3Exception ex)
{
context.Logger.LogLine($"AmazonS3Exception: {ex.Message}");
context.Logger.LogLine($"Error Code: {ex.ErrorCode}");
context.Logger.LogLine($"Request ID: {ex.RequestId}");
context.Logger.LogLine($"Status Code: {ex.StatusCode}");
return new APIGatewayProxyResponse
{
StatusCode = 500,
Body = $"AmazonS3Exception: {ex.Message}"
};
}
catch (Exception ex)
{
context.Logger.LogLine($"Exception during S3 upload: {ex}");
return new APIGatewayProxyResponse
{
StatusCode = 500,
Body = $"Exception during S3 upload: {ex.Message}"
};
}
}
private string GetBoundary(string contentType)
{
if (contentType == null)
throw new ArgumentNullException(nameof(contentType));
var elements = contentType.Split(' ');
foreach (var element in elements)
{
if (element.StartsWith("boundary="))
{
return element.Substring("boundary=".Length).Trim('"');
}
}
throw new InvalidOperationException("Boundary not found in content type");
}
}
}
I am able to see the logs, like the employeeEmail and details of the image, but when uploading it is taking time and giving timeout error.
Upvotes: -1
Views: 32