.NET6迁移时APIGatewayHttpApiV2ProxyRequest转换错误求助
迁移背景
从.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¶meter1=value2¶meter2=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

