AWS Lambda - Supporting binary response in ASP.NET Core 6
Describe the bug
Hello,
I'm creating an ASP.NET Core 6 Rest API running in a lambda behind an API Gateway. We have somme issues since we would like to return image/webp content and we are not able to do it.
We've seen that a solution exists for ASP.NET Core 2 by calling the following method :
RegisterResponseContentEncodingForContentType("image/webp", ResponseContentEncoding.Base64);
But unforunately we didn't find any information or tutorial to do the same thing using ASP.NET Core 6 cause the lambda support is done as below in the Program.cs file :
builder.Services.AddAWSLambdaHosting(LambdaEventSource.RestApi);
Is there any way to register image/webp conte type for Base64 transformation in ASP.NET Core 6 using the builder.Services.AddAWSLambdaHosting(LambdaEventSource.RestApi); method ?
Thanks
Expected Behavior
Be able to register content-types for Base64 transformation in ASP.NET Core 6 Program.cs file
Current Behavior
Unable to register content-types for Base64 transformation in ASP.NET Core 6 Program.cs file
Reproduction Steps
- Create an ASP.NET Core 6 rest api
- Add the lambda support in the Program.cs file
(builder.Services.AddAWSLambdaHosting(LambdaEventSource.RestApi);) - Return a webp image in your endpoint :
[HttpGet] public ActionResult GetWebp() { var image = System.IO.File.ReadAllBytes("myImage.webp"); return File(image, "image/webp"); } }
Possible Solution
No response
Additional Information/Context
No response
AWS .NET SDK and/or Package version used
Amazon.Lambda.AspNetCoreServer.Hosting 1.6.0
Targeted .NET Platform
ASP.NET Core 6.0
Operating System and version
Any
I'm facing the same issue, a solution would be great.
@hugohlln Good morning. Thanks for opening the issue. Please refer to https://github.com/aws/aws-lambda-dotnet/discussions/1527, it might help. You need to use LambdaEventSource.HttpApi and return APIGatewayHttpApiV2ProxyResponse.
Hi @ashishdhingra,
Thanks for your reply.
We wan't to keep our current returned object ActionResult ant not APIGatewayHttpApiV2ProxyResponse in our controllers.
The fact is that if we want in the future to run the project in another execution environment than a Lambda we will be obliged to edit our code and this is not the goal.
There is no way to register image/webp to tranformation for Base64 when adding the lambda hosting service to the service collection ?
What I did for the moment is creating my own AddAWSLambdaHosting service and my own APIGatewayRestApiLambdaRuntimeSupportServer where I can register my transformation for Base64 :
Custom APIGatewayRestApiLambdaRuntimeSupportServer :
public class APIGatewayRestApiLambdaRuntimeSupportServerCustom : LambdaRuntimeSupportServer
{
/// <summary>
/// Create instances
/// </summary>
/// <param name="serviceProvider">The IServiceProvider created for the ASP.NET Core application</param>
public APIGatewayRestApiLambdaRuntimeSupportServerCustom(IServiceProvider serviceProvider)
: base(serviceProvider)
{
}
/// <summary>
/// Creates HandlerWrapper for processing events from API Gateway REST API
/// </summary>
/// <param name="serviceProvider"></param>
/// <returns></returns>
protected override HandlerWrapper CreateHandlerWrapper(IServiceProvider serviceProvider)
{
var handler = new APIGatewayRestApiMinimalApi(serviceProvider).FunctionHandlerAsync;
return HandlerWrapper.GetHandlerWrapper(handler, serviceProvider.GetRequiredService<ILambdaSerializer>());
}
/// <summary>
/// Create the APIGatewayProxyFunction passing in the ASP.NET Core application's IServiceProvider
/// </summary>
public class APIGatewayRestApiMinimalApi : APIGatewayProxyFunction
{
/// <summary>
/// Create instances
/// </summary>
/// <param name="serviceProvider">The IServiceProvider created for the ASP.NET Core application</param>
public APIGatewayRestApiMinimalApi(IServiceProvider serviceProvider)
: base(serviceProvider)
{
this.RegisterResponseContentEncodingForContentType("image/webp", ResponseContentEncoding.Base64);
}
}
}
Custom AddAWSLambdaHosting:
/// <summary>
/// Enum for the possible event sources that will send HTTP request into the ASP.NET Core Lambda function.
/// </summary>
public enum LambdaEventSourceCustom
{
/// <summary>
/// API Gateway REST API
/// </summary>
RestApi,
/// <summary>
/// API Gateway HTTP API
/// </summary>
HttpApi,
/// <summary>
/// ELB Application Load Balancer
/// </summary>
ApplicationLoadBalancer,
/// <summary>
/// API Gateway REST API Custom
/// </summary>
RestApiCustom
}
/// <summary>
/// Extension methods to IServiceCollection.
/// </summary>
public static class ServiceCollectionExtensions
{
/// <summary>
/// Add the ability to run the ASP.NET Core Lambda function in AWS Lambda. If the project is not running in Lambda
/// this method will do nothing allowing the normal Kestrel webserver to host the application.
/// </summary>
/// <param name="services"></param>
/// <param name="eventSource"></param>
/// <returns></returns>
public static IServiceCollection AddAWSLambdaHostingCustom(this IServiceCollection services, LambdaEventSourceCustom eventSource)
{
// Not running in Lambda so exit and let Kestrel be the web server
return services.AddAWSLambdaHostingCustom(eventSource, (Action<HostingOptions>?)null);
}
/// <summary>
/// Add the ability to run the ASP.NET Core Lambda function in AWS Lambda. If the project is not running in Lambda
/// this method will do nothing allowing the normal Kestrel webserver to host the application.
/// </summary>
/// <param name="services"></param>
/// <param name="eventSource"></param>
/// <param name="configure"></param>
/// <returns></returns>
public static IServiceCollection AddAWSLambdaHostingCustom(this IServiceCollection services, LambdaEventSourceCustom eventSource, Action<HostingOptions>? configure = null)
{
// Not running in Lambda so exit and let Kestrel be the web server
if (string.IsNullOrEmpty(Environment.GetEnvironmentVariable("AWS_LAMBDA_FUNCTION_NAME")))
return services;
var hostingOptions = new HostingOptions();
if (configure != null)
configure.Invoke(hostingOptions);
services.TryAddSingleton<ILambdaSerializer>(hostingOptions.Serializer ?? new DefaultLambdaJsonSerializer());
var serverType = eventSource switch
{
LambdaEventSourceCustom.HttpApi => typeof(APIGatewayHttpApiV2LambdaRuntimeSupportServer),
LambdaEventSourceCustom.RestApi => typeof(APIGatewayRestApiLambdaRuntimeSupportServer),
LambdaEventSourceCustom.ApplicationLoadBalancer => typeof(ApplicationLoadBalancerLambdaRuntimeSupportServer),
LambdaEventSourceCustom.RestApiCustom => typeof(APIGatewayRestApiLambdaRuntimeSupportServerCustom),
_ => throw new ArgumentException($"Event source type {eventSource} unknown")
};
Utilities.EnsureLambdaServerRegistered(services, serverType);
return services;
}
}
And in my Program.cs:
builder.Services.AddAWSLambdaHostingCustom(LambdaEventSourceCustom.RestApiCustom);
I really hope that a best solution will be provided and that we will be able to add those kind of transformation directly in the Program.cs file when adding the service to the service collection
@hugohlln very good idea, I will try it too.