Пользовательский заголовок не добавляется в окончательный HTTP-ответ - класс APIGatewayHttpApiV2ProxyResponse из AWS .NET Lambda SDK

Описание

Я работаю с AWS Lambda, НО без пакета Amazon.Lambda.AspNetCoreServer все работает нормально, за исключением того факта, что я добавляю некоторые основные настраиваемые заголовки ответов, такие как тип содержимого JSON, и ничего не добавляется в окончательные заголовки ответов HTTP.

В моем конкретном случае я не использую Amazon.Lambda.AspNetCoreServer, потому что я создаю шаблон бессерверной инфраструктуры.

    public class GetUserByIdFunction : FunctionBase
    {
        private IUserRepository _userRepository;

        protected override void ConfigureServices(IServiceCollection serviceCollection)
        {
            var connString = Configuration["UserServiceDbContextConnectionString"];

            // serviceCollection.AddDbContext<UserContext>(options => options.UseMySql(connString));
            serviceCollection.AddDbContext<UserContext>(options => options.UseInMemoryDatabase(connString));//temporarily

            serviceCollection.AddScoped<IUserRepository, UserRepository>();
        }

        protected override void Configure(IServiceProvider serviceProvider)
        {
            _userRepository = serviceProvider.GetService<IUserRepository>();
        }

        // Invoked by AWS Lambda at runtime
        public GetUserByIdFunction()
        {
        }

        public GetUserByIdFunction(
            IConfiguration configuration,
            IUserRepository userRepository)
        {
            // Constructor used by tests
            _userRepository = userRepository;
        }


        public async Task<APIGatewayHttpApiV2ProxyResponse> Handle(APIGatewayHttpApiV2ProxyRequest request, ILambdaContext context)
        {
            LogFunctionMetadata(request, context);

            if (!RunningAsLocal) ConfigureDependencies();

            var userId = Guid.Parse(request.PathParameters["userid"]);

            var user = await _userRepository.GetByIdAsync(userId);
            if (user == null) return NotFound();

            return Ok(user);
        }
    }
    public abstract class FunctionBase
    {
        protected IConfiguration Configuration { get; private set; }
        protected bool RunningAsLocal = false;

        public FunctionBase() => Configuration = ConfigurationService.Instance.Configuration;

        public FunctionBase(IConfiguration configuration)
        {
            Configuration = configuration;
            RunningAsLocal = true;
        }

        protected void ConfigureDependencies()
        {
            var serviceCollection = new ServiceCollection();
            ConfigureServices(serviceCollection);
            Configure(serviceCollection.BuildServiceProvider());
        }

        protected abstract void ConfigureServices(IServiceCollection serviceCollection);
        protected abstract void Configure(IServiceProvider serviceProvider);

        protected void LogFunctionMetadata(APIGatewayHttpApiV2ProxyRequest request, ILambdaContext context)
        {
            LambdaLogger.Log($"CONTEXT {Serialize(context.GetMainProperties())}");
            LambdaLogger.Log($"EVENT: {Serialize(request.GetMainProperties())}");
        }

        protected APIGatewayHttpApiV2ProxyResponse Ok() =>
            new APIGatewayHttpApiV2ProxyResponse()
            {
                StatusCode = (int) HttpStatusCode.OK,
                Headers = new Dictionary<string, string>
                {
                    {"Content-Type", "application/json"}
                }
            };

        protected APIGatewayHttpApiV2ProxyResponse NotFound() =>
            new APIGatewayHttpApiV2ProxyResponse()
            {
                StatusCode = (int) HttpStatusCode.NotFound,
                Headers = new Dictionary<string, string>
                {
                    {"Content-Type", "application/json"}
                }
            };
    }

Единственная проблема заключается в том, что любой заголовок, добавленный к классу APIGatewayHttpApiV2ProxyResponse, не добавляется к окончательному ответу HTTP, как ожидалось.

Примечание: я уже пробовал использовать SetHeaderValues, например:

      protected APIGatewayHttpApiV2ProxyResponse Ok(object body)
        { 
            var response = new APIGatewayHttpApiV2ProxyResponse()
            {
                StatusCode = (int) HttpStatusCode.OK,
                Body = Serialize(body)
            };
            
            response.SetHeaderValues("Content-Type", "application/json", false);
            response.SetHeaderValues("Access-Control-Allow-Origin", "*", false);
            response.SetHeaderValues("Access-Control-Allow-Credentials", "true", false);

            return response;
        }

Шаги размножения

git clone https://github.com/RichardSilveira/UserServerlessMicroservice cd UserServerlessMicroservice cd src/userService npm i -g serverless

Примечание. Бессерверная структура создает уровень абстракции при облачной информации, это означает, что стек будет развернут в учетной записи AWS, вы можете легко удалить стек - за этот стек, который вы загружаете, плата не взимается.

provider:
  name: aws
  profile: default
  runtime: dotnetcore3.1
  stage: dev
  region: sa-east-1

Вы можете указать имя профиля из файла учетных данных AWS на локальном компьютере в файле serverless.yml, добавив profile: <name>, например, в приведенном выше примере. Это необязательно, если вы ничего не сделаете, будет использоваться профиль по умолчанию.

build sls deploy -v

Журналы

N/A

Среда

Я считаю, что лучше показать весь мой файл описания проекта.

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFramework>netcoreapp3.1</TargetFramework>
    <GenerateRuntimeConfigurationFiles>true</GenerateRuntimeConfigurationFiles>
    <PackageId>aws-csharp</PackageId>
    <RootNamespace>UserService</RootNamespace>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Amazon.Lambda.APIGatewayEvents" Version="2.1.0" />
    <PackageReference Include="Amazon.Lambda.Core" Version="1.1.0" />
    <PackageReference Include="Amazon.Lambda.Serialization.SystemTextJson" Version="2.0.1" />
    <PackageReference Include="EventStore.Client" Version="20.6.0" />
    <PackageReference Include="FluentValidation" Version="9.0.1" />
    <PackageReference Include="MediatR" Version="8.1.0" />
    <PackageReference Include="MediatR.Extensions.Microsoft.DependencyInjection" Version="8.1.0" />
    <PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="3.1.6" />
    <PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="3.1.6" />
    <PackageReference Include="Microsoft.Extensions.Configuration" Version="3.1.6" />
    <PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="3.1.6" />
    <PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="3.1.6" />
    <PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="3.1.6" />
    <PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="3.1.6" />
    <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="3.1.6" />
    <PackageReference Include="MySql.Data" Version="8.0.21" />
    <PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="3.1.2" />
  </ItemGroup>

  <ItemGroup>
    <DotNetCliToolReference Include="Amazon.Lambda.Tools" Version="2.2.0" />
  </ItemGroup>

  <ItemGroup>
    <None Update="appsettings.json">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </None>
    <None Update="appsettings.dev.json">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </None>
    <None Update="appsettings.local.json">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </None>
  </ItemGroup>

</Project>

Есть предположения?

Заранее спасибо!


person Richard Lee    schedule 04.09.2020    source источник


Ответы (2)


Вы добавили application / json в типы мультимедиа API Gateway? Или это по умолчанию? Я знаю, что мне пришлось добавить вроде application / octet-stream.

person Tim Bassett    schedule 04.09.2020

Решено,

Создание ответа, как показано ниже, отлично работает

           new APIGatewayHttpApiV2ProxyResponse()
            {
                StatusCode = (int) HttpStatusCode.OK,
                Body = Serialize(body),
                Headers = new Dictionary<string, string>
                {
                    {"Content-Type", "application/json"},
                    {"Access-Control-Allow-Origin", "*"},
                    {"Access-Control-Allow-Credentials", "true"}
                }
            };

Вместо того, чтобы назначать другой словарь свойству Headers

person Richard Lee    schedule 04.09.2020