You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET6迁移时APIGatewayHttpApiV2ProxyRequest转换错误求助

.NET Core 3.1迁移至.NET6后Lambda序列化转换错误解决

迁移背景

从.NET Core 3.1迁移到.NET6,更新了以下NuGet包:

  • Amazon.Lambda.Serialization.SystemTextJson:V2.1.0 → v2.3.1
  • Amazon.Lambda.Core:v2.0.0 → v2.1.0

错误信息

System.ArgumentException: 无法将类型为'System.IO.MemoryStream'的对象转换为类型'Amazon.Lambda.APIGatewayEvents.APIGatewayHttpApiV2ProxyRequest'。
调用栈:
at System.RuntimeType.TryChangeType(Object value, Binder binder, CultureInfo culture, Boolean needsSpecialCast) 
at System.RuntimeType.CheckValue(Object value, Binder binder, CultureInfo culture, BindingFlags invokeAttr)
at System.Reflection.MethodBase.CheckArguments(StackAllocedArguments& stackArgs, ReadOnlySpan`1 parameters, Binder binder, BindingFlags invokeAttr, CultureInfo culture, Signature sig)

相关代码

Serverless Lambda处理代码

//using namespaces

namespace ProjectAPI.Commands.Functions
{
    public class External : EntryFunction
    {
        public async Task<APIGatewayHttpApiV2ProxyResponse> CreateRunBookingAsync(APIGatewayHttpApiV2ProxyRequest request, ILambdaContext context)
        {
            try
            {
                var command = request.GetBodyAs<CreateRetryBatchPushLocusCommand>();
                var response = await Send(request, command);
                return ProxyResponse(response, context?.Logger);
            }
            catch (Exception e)
            {
                var response = new EntryExceptionResponse(e);
                return ProxyResponse(response, context?.Logger);
            }
        }
    }
}

基类:EntryFunction

//using namespaces
namespace ProjectAPI.Commands {
public class EntryFunction : BaseEntryFunction {
    protected override BaseDependencyResolver BaseDependencyResolver => new DependencyResolver();

    protected override IMediator ProvideMediatorInstance() {
        return BaseDependencyResolver.ServiceProvider.GetService<IMediator>();
    }
  }}

基类:BaseEntryFunction

//using namespaces

[assembly: LambdaSerializer(typeof(SourceGeneratorLambdaJsonSerializer<Common.API.HttpApiJsonSerializerContext>))]

namespace Common.API
{
    [JsonSerializable(typeof(APIGatewayHttpApiV2ProxyRequest))]
    [JsonSerializable(typeof(APIGatewayHttpApiV2ProxyResponse))]
    public partial class HttpApiJsonSerializerContext : JsonSerializerContext
    {
    }
    
    public abstract class BaseEntryFunction
    {
        protected IMediator mediator;

        protected IConfiguration Configuration => BaseDependencyResolver.ServiceProvider.GetService<IConfiguration>();

        protected abstract BaseDependencyResolver BaseDependencyResolver { get; }

        protected BaseEntryFunction()
        {
        }

        protected virtual IMediator ProvideMediatorInstance()
        {
            mediator ??= BaseDependencyResolver.ServiceProvider.GetService<IMediator>();
            return mediator;
        }    
        
        protected Task<TResponse> Send<TResponse>(APIGatewayHttpApiV2ProxyRequest proxyRequest, IRequest<TResponse> request, CancellationToken cancellationToken = default )
        {
            return mediator.Send(request, cancellationToken);
        }
    }
}

依赖解析代码

//using statements

namespace DependencyResolution.Queries
{
    public class DependencyResolver : BaseDependencyResolver
    {
        public DependencyResolver(Action<IServiceCollection> registerServices = null) : base(registerServices)
        {
        }

        protected override void ConfigureServices(ServiceCollection serviceCollection)
        {
            serviceCollection.AddTransient<IEnvironmentService, EnvironmentService>();
            serviceCollection.AddTransient<IConfigurationService, ConfigurationService>
                (provider => new ConfigurationService(provider.GetService<IEnvironmentService>())
                {
                    CurrentDirectory = CurrentDirectory
                });
           
            // Register DbContext class
            //dbcotext registration here 
            ...............
            var intermediateServiceProvider = serviceCollection.BuildServiceProvider();
            var configService = intermediateServiceProvider.GetService<IConfigurationService>();
            var configuration = configService?.GetConfiguration();
            serviceCollection.ConfigureDatabase(configuration);
            var applicationAssembly = typeof(GetCustomerQuery).GetTypeInfo().Assembly;
            var sharedAssembly = typeof(AppRequest<>).GetTypeInfo().Assembly;
            //serviceCollection.AddMediatR(applicationAssembly, sharedAssembly);
            serviceCollection.AddMediatR(cfg => cfg.RegisterServicesFromAssemblies(applicationAssembly, sharedAssembly));

            serviceCollection.AddFluentValidation(new[] { applicationAssembly, sharedAssembly });
            RegisterServices?.Invoke(serviceCollection);
        }
    }
}

请求Payload示例

{
  "version": "2.0",
  "routeKey": "$default",
  "rawPath": "/path/to/resource",
  "rawQueryString": "parameter1=value1&parameter1=value2&parameter2=value",
  "cookies": [ "cookie1", "cookie2" ],
  "headers": {
    "Header1": "value1",
    "Header2": "value2"
  },
  "queryStringParameters": {
    "parameter1": "value1,value2",
    "parameter2": "value"
  },
  "requestContext": {
    "accountId": "123456789012",
    "apiId": "api-id",
    "authentication": {
      "clientCert": {
        "clientCertPem": "CERT_CONTENT",
        "subjectDN": "www.example.com",
        "issuerDN": "Example issuer",
        "serialNumber": "a1:a1:a1:a1:a1:a1:a1:a1:a1:a1:a1:a1:a1:a1:a1:a1",
        "validity": {
          "notBefore": "May 28 12:30:02 2019 GMT",
          "notAfter": "Aug  5 09:36:04 2021 GMT"
        }
      }
    },
    "authorizer": {
      "jwt": {
        "claims": {
          "claim1": "value1",
          "claim2": "value2"
        },
        "scopes": [ "scope1", "scope2" ]
      }
    },
    "domainName": "id.execute-api.us-east-1.amazonaws.com",
    "domainPrefix": "domain-id",
    "http": {
      "method": "POST",
      "path": "/path/to/resource",
      "protocol": "HTTP/1.1",
      "sourceIp": "IP",
      "userAgent": "agent"
    },
    "requestId": "request-id",
    "routeId": "route-id",
    "routeKey": "$default-route",
    "stage": "$default-stage",
    "time": "12/Mar/2020:19:03:58 +0000",
    "timeEpoch": 1583348638390
  },
  "body": "Hello from Lambda",
  "pathParameters": { "parameter1": "value1" },
  "isBase64Encoded": false,
  "stageVariables": {
    "stageVariable1": "value1",
    "stageVariable2": "value2"
  }
}

解决方案

1. 同步更新Amazon.Lambda.APIGatewayEvents包

当前仅更新了序列化和Core包,Amazon.Lambda.APIGatewayEvents包版本可能与新序列化包不兼容。将其更新到与Amazon.Lambda.Serialization.SystemTextJson v2.3.1匹配的最新版本(可查看NuGet包依赖关系确认兼容版本)。

2. 完善JsonSerializerContext的类型配置

新版本的SourceGeneratorLambdaJsonSerializer依赖源生成的类型信息,需确保所有嵌套类型都被包含:
修改HttpApiJsonSerializerContext的特性配置,添加TypeInfoPolicy = JsonTypeInfoPolicy.All以自动包含目标类型的所有嵌套类型:

[JsonSerializable(typeof(APIGatewayHttpApiV2ProxyRequest), TypeInfoPolicy = JsonTypeInfoPolicy.All)]
[JsonSerializable(typeof(APIGatewayHttpApiV2ProxyResponse), TypeInfoPolicy = JsonTypeInfoPolicy.All)]
[JsonSerializable(typeof(CreateRetryBatchPushLocusCommand))]
public partial class HttpApiJsonSerializerContext : JsonSerializerContext
{
}

注:需添加CreateRetryBatchPushLocusCommand的序列化配置,因为代码中用到了request.GetBodyAs<CreateRetryBatchPushLocusCommand>()。

3. 验证Lambda序列化器注册

确保程序集级别的LambdaSerializer属性没有被其他配置覆盖,且SourceGeneratorLambdaJsonSerializer的泛型参数指向正确的HttpApiJsonSerializerContext。

4. 临时切换序列化器排查问题

如果问题仍存在,暂时将SourceGeneratorLambdaJsonSerializer替换为旧版的SystemTextJsonSerializer,验证是否是源生成器的配置问题:

[assembly: LambdaSerializer(typeof(SystemTextJsonSerializer))]

若替换后问题解决,再重新调试源生成器的配置细节。

5. 检查Lambda handler配置

确认Lambda函数的handler配置格式正确,例如:ProjectAPI::ProjectAPI.Commands.Functions.External::CreateRunBookingAsync,确保命名空间、类名和方法名无误。

内容的提问来源于stack exchange,提问作者Tika Ram

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 01:32:01