Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AWS Lambda - Supporting binary response in ASP.NET Core 6 #1574

Open
hugohlln opened this issue Aug 30, 2023 · 6 comments
Open

AWS Lambda - Supporting binary response in ASP.NET Core 6 #1574

hugohlln opened this issue Aug 30, 2023 · 6 comments
Labels
feature-request A feature should be added or improved. module/aspnetcore-support p2 This is a standard priority issue queued

Comments

@hugohlln
Copy link

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

@hugohlln hugohlln added bug This issue is a bug. needs-triage This issue or PR still needs to be triaged. labels Aug 30, 2023
@brignolij
Copy link

I'm facing the same issue, a solution would be great.

@ashishdhingra ashishdhingra transferred this issue from aws/aws-sdk-net Aug 30, 2023
@ashishdhingra
Copy link
Contributor

@hugohlln Good morning. Thanks for opening the issue. Please refer to #1527, it might help. You need to use LambdaEventSource.HttpApi and return APIGatewayHttpApiV2ProxyResponse.

@ashishdhingra ashishdhingra added response-requested Waiting on additional info and feedback. Will move to close soon in 7 days. and removed needs-triage This issue or PR still needs to be triaged. labels Aug 30, 2023
@hugohlln
Copy link
Author

hugohlln commented Aug 31, 2023

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 ?

@hugohlln
Copy link
Author

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

@hugohlln
Copy link
Author

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

@brignolij
Copy link

@hugohlln very good idea, I will try it too.

@github-actions github-actions bot removed the response-requested Waiting on additional info and feedback. Will move to close soon in 7 days. label Sep 1, 2023
@dscpinheiro dscpinheiro changed the title AWS Lamdba - Supporting binary response in ASP.NET Core 6 AWS Lambda - Supporting binary response in ASP.NET Core 6 Sep 5, 2023
@ashishdhingra ashishdhingra added feature-request A feature should be added or improved. p2 This is a standard priority issue queued and removed bug This issue is a bug. needs-review labels Sep 8, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature-request A feature should be added or improved. module/aspnetcore-support p2 This is a standard priority issue queued
Projects
None yet
Development

No branches or pull requests

3 participants