Parece que o comportamento padrão da caixa mudou entre Amazon.Lambda.Serialization.Json.JsonSerializer
e Amazon.Lambda.Serialization.SystemTextJson.LambdaJsonSerializer
.
Aqui está um exemplo de código para testar a diferença:
// create an instance to serialize
var record = new Record {
Foo = "Hello world!"
};
// show serialization with original Lambda serializer based on Newtonsoft.Json
var oldSerializer = SerializeWith(record, new Amazon.Lambda.Serialization.Json.JsonSerializer());
Console.WriteLine($"Amazon.Lambda.Serialization.Json.JsonSerializer: {oldSerializer}");
// show serialization with new Lambda serializer based on System.Text.Json
var newSerializer = SerializeWith(record, new Amazon.Lambda.Serialization.SystemTextJson.LambdaJsonSerializer());
Console.WriteLine($"Amazon.Lambda.Serialization.SystemTextJson.LambdaJsonSerializer: {newSerializer}");
// show serialization with System.Json.Text
var jsonTextSerializer = System.Text.Json.JsonSerializer.Serialize<Record>(record);
Console.WriteLine($"System.Text.Json.JsonSerializer: {jsonTextSerializer}");
// local functions
string SerializeWith<T>(T value, Amazon.Lambda.Core.ILambdaSerializer serializer) {
using var buffer = new MemoryStream();
serializer.Serialize<T>(value, buffer);;
return System.Text.Encoding.UTF8.GetString(buffer.ToArray());
}
O código acima produz a seguinte saída:
Amazon.Lambda.Serialization.Json.JsonSerializer: {"Foo":"Hello world!"}
Amazon.Lambda.Serialization.SystemTextJson.LambdaJsonSerializer: {"foo":"Hello world!"}
System.Text.Json.JsonSerializer: {"Foo":"Hello world!"}
Concordo que não deveria ter trocado a caixa entre as 2 bibliotecas. Acho que faltam testes para solicitações e respostas personalizadas, já que os testes agora se concentram principalmente em eventos da AWS.
Agora que isso foi enviado, alterar o comportamento padrão é realmente inviável. Minha sugestão é adicionar um novo construtor que aceite um enum para o estilo de maiúsculas e minúsculas para que você possa declarar a capitalização que deseja usar. Eu poderia então atualizar os modelos para usar o novo construtor. Como você se sente sobre essa solução?
Não sei qual foi a ideia aqui. Eu entendo que você não quer quebrar pessoas que podem ter ficado dependentes. Parece que o erro foi acreditar que a AWS tem consistência na nomenclatura de campos JSON (ou seja, AWSNamingPolicy
). Isso não. Alguns serviços usam Pascal-casing, como CloudFormation:
https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/crpg-ref-responses.html
Alterar maiúsculas e minúsculas e não respeitar o comportamento padrão de System.Text.Json
é uma falha fatal, IMHO. Considere liberar um Amazon.Lambda.Serialization.SystemTextJson.LambdaJsonSerializerV2
e colocar o antigo no gelo.
Para esclarecer, como não estou familiarizado com como isso funciona, a declaração de atributo do assembly é usada apenas para desserialização, correto?
[assembly: LambdaSerializer(typeof(Amazon.Lambda.SystemTextJson.LambdaJsonSerializer))]
No entanto, será mesmo necessário se eu usar essa assinatura do manipulador?
Task<Stream> FunctionHandlerAsync(Stream stream, ILambdaContext context)
O que acontece se não houver declaração LambdaSerializerAttribute
para o método assembly ou de ponto de entrada?
@normj uma opção pode ser adicionar atributos para nomear explicitamente as propriedades json e, portanto, respeitar a nomenclatura, independentemente da caixa
Eu concordaria com essa sugestão - é um trabalho tedioso e único adicioná-los, mas eles estão sempre corretos.
@normj IMHO este é um problema de implementação que precisa / deve ser
@ 3GDXC Concordo que é um bug de implementação. Só pensando na solução. Atualmente no pacote temos um serializador chamado LambdaJsonSerializer
. E se adicionarmos PascalCaseLambdaJsonSerializer
e CamelCaseLambdaJsonSerializer
serializador que se estende de LambdaJsonSerializer
. Eu poderia mudar os modelos para usar PascalCaseLambdaJsonSerializer
para manter o comportamento existente. É uma espécie de versão mais explícita da sugestão @bjorg de ter um LambdaJsonSerializerV2.
@normj IMHO, seria melhor e evitar confusão adicionar os atributos JsonPropertyName às mensagens para que, independentemente da configuração / opções do serializador, o Json resultante aderisse à nomenclatura do atributo.
Eu entendo perfeitamente por que você está relutante em introduzir mais uma alteração significativa (com a correção) em questão de dias após o lançamento do suporte .NET 3.1; e se nós (royal we) tivéssemos vários problemas UP-FOR-GRABS , nenhum teste de unidade / regressão, a comunidade poderia ajudar com eles para fazer a implementação evoluir e testar antes do lançamento.
Fico feliz em ajudar se / quando necessário, basta dizer a palavra.
ótimo trabalho até agora, adorando ver o crescimento do suporte do aws lamba e .net
@ 3GDXC Lembre-se de que a https://github.com/aws/aws-lambda-dotnet/blob/master/Libraries/src/Amazon.Lambda.APIGatewayEvents/APIGatewayProxyResponse. cs # L18
O problema é para objetos de resposta que outras pessoas criam onde eu não controlo se eles usam o atributo JsonPropertyName ou não.
@normj bom ponto; pode ser o aviso também deve incluir SEMPRE usar atributos JsonPropertyName para impor a nomenclatura explícita de suas propriedades e / ou contratos de dados (melhores práticas)
@normj uma alternativa pode ser abstrair o JsonSerializerOptions em uma classe LambdaSerializerOptions e adicionar as opções como um parâmetro de construtor no atributo para que o serializador possa ter opções personalizadas que o desenvolvedor pode substituir em um nível de assembly / método
Que tal sinalizá-lo como uma regressão e corrigi-lo como uma alteração significativa agora, em vez de espalhar mais danos? Eu chamo isso de _harm_ porque LambdaJsonSerializer
, que é baseado em System.Text.Json
, não respeita o comportamento padrão de como serializar propriedades. É claro que usar [JsonPropertyName]
corrige isso, mas exigir que todos façam algo para conter um comportamento indesejado parece algo pesado.
Quantas pessoas continuarão a encontrar isso como _?!?!? _ Momento em que adotarem LambdaJsonSerializer
como seu serializador padrão?
Olá, estou encontrando este problema nas funções de etapa após alternar as tarefas lambda para .Net 3.1 + o novo serializador. Está causando estragos porque a saída agora está em camelcase, então a próxima forma de máquina de estado tenta avaliar o novo JSON usando o Amazon States Language e lança uma exceção Step Function.
Há uma solução alternativa complicada para o momento. Definindo LAMBDA_NET_SERIALIZER_DEBUG=true
na variável de ambiente, _.options
nunca é definido no serializador, fazendo com que o caso seja retornado sem alterações. Não tenho certeza se isso resultará em outras repercussões além da emissão de JSON adicional nos Logs do Cloudwatch.
https://github.com/aws/aws-lambda-dotnet/blob/master/Libraries/src/Amazon.Lambda.Serialization.SystemTextJson/LambdaJsonSerializer.cs#L69 -L90
IMO, seria um saco decorar todos os nossos modelos com a decoração [JsonPropertyName]
pois nossos modelos estão enterrados em várias bibliotecas de nugets. Idealmente, gostaria que o comportamento padrão retornasse ao PascalCasing original como antes, mas estou bem em usar um PascalCaseLambdaJsonSerializer
explícito com os lambdas quando ele é chamado em nosso projeto Step Function.
Obrigado!
Tenho certeza de que essa solução alternativa é um bug.
Bom ponto sobre as estruturas de dados definidas por assemblies upstream.
Não sei que efeito colateral teria em outras coisas sem os atributos [JsonPropertyName]
, mas usar o construtor LambdaJsonSerializer
que permite personalizar o serializador JSON pode ser revertido para o comportamento PascalCase padrão definindo JsonSerializerOptions.PropertyNamingPolicy
para null
.
Vinculando ao problema # 628, pois está relacionado a esta discussão.
Eu acho que isso está relacionado.
Olhando para APIGatewayProxyRequest.cs , percebi que não há anotações [JsonPropertyName]
. A única razão pela qual isso funciona é porque a) LambdaJsonSerializer
padroniza para desserialização sem distinção entre maiúsculas e minúsculas eb) LambdaJsonSerializer
usa "camel-case" na serialização.
Eu posso ver como isso economizou muitas horas na anotação de todas as classes de solicitação / resposta nos vários assemblies auxiliares, mas significa que quando usamos os assemblies auxiliares, temos que usar LambdaJsonSerializer
em nossas funções.
Em retrospecto, não faria mais sentido colocar a anotação [LambdaSerializer(typeof(Amazon.Lambda.Serialization.Json.JsonSerializer))]
na classe POCO usada pelo manipulador de função em vez da própria classe de função? Parece que, em última análise, a função deve usar o serializador que corresponde às classes de solicitação / resposta.
@bjorg IMO o POCO é o local errado para ter metadados de atributos sobre a serialização que deve ser usada; o POCO deve se preocupar apenas com o seu domínio, ou seja, os atributos de validação do modelo e tipo / nomenclatura da propriedade; a serialização deve respeitar / usar essas anotações de modelo.
IMHO o atributo LambdaSerializer deve ser alterado para aceitar o tipo de serialização, por exemplo. Amazon.Lambda.Serialization.Json.JsonSerializer com opções de serialização opcionais; se a opção não for fornecida, as configurações padrão e compatíveis serão usadas.
Mas o POCO precisa ser anotado com os atributos corretos do serializador: [JsonProperty]
para Newtonsoft e [JsonPropertyName]
para System.Text.Json. Conseqüentemente, o POCO está vinculado ao serializador.
Parece que [DataMember]
será suportado por Newtonsoft.Json
e System.Text.Json
. No entanto, não até o .NET 5 para o último. :(
https://github.com/dotnet/runtime/issues/29975
Nesse ínterim, uma solução seria anotar todos os POCOs com [DataMember]
e [JsonPropertyName]
. Ambos os atributos são definidos no .NET Core 3.1 e, portanto, não requerem dependências externas adicionais.
Isso não garantiria serialização / desserialização consistente para todas as classes, pelo menos para nomes de propriedades? Os conversores precisariam ser registrados pelas implementações ILambdaSerialize
.
O problema vinculado aí foi encerrado. Meu entendimento da leitura superficial desse tópico é que eles não pretendem suportá-lo: https://github.com/dotnet/runtime/issues/29975#issuecomment -609985802
Sim. Eu li errado. Eu vi o link 5.0 e tirei a conclusão errada.
Publiquei um PR https://github.com/aws/aws-lambda-dotnet/pull/636 para abordar o problema. Eu gostaria de receber feedback ou, melhor ainda, baixar a versão de visualização do link no PR e ajudar a verificar se a mudança funciona para você.
Em primeiro lugar, obrigado por resolver isso tão rapidamente. Desculpe por ter arruinado seu sábado.
À primeira vista, parece bom. No momento, estou removendo todas as referências de Newtonsoft.Json
e não estou em um estado em que possa verificar a correção, infelizmente. Por enquanto, simplesmente copiei a classe do serializador problemático e removi a instrução ofensiva. Espero que amanhã, EOD, eu possa testar essa alteração em meu branch de desenvolvimento.
A primeira coisa que vem à mente são anotações potencialmente ausentes. Houve alguma estrutura de dados de resposta que não usasse [DataMember]
e, em vez disso, dependesse do invólucro de camelo implícito?
@bjorg Não se preocupe. Depois de uma semana de reuniões, escrevendo documentos e ajudando as crianças na escola, foi muito reconfortante ter alguns momentos de silêncio e fazer alguns códigos aos sábados.
Tínhamos o potencial de perder a anotação [DataMember]
com o serializador Newtonsoft. Não estou muito preocupado com isso porque, para tipos conhecidos, temos o teste para isso. Neste caso, minha lacuna estava faltando testes em respostas personalizadas.
Seria possível liberar -rc1
? A alternativa, AFAIK, é para mim hackear meus arquivos _.csproj_ com as constantes de compilação corretas habilitadas. Existe outra maneira?
@bjorg No PR, há um link para um arquivo zip contendo pacotes NuGet pré-construídos. Você pode configurar uma fonte NuGet local e colocar os pacotes lá?
Aprendi algo novo hoje: como ter um feed local. Acabou sendo muito fácil no .NET Core (consulte o artigo do SO ).
Meu feedback mais pertinente é expor _options
como uma propriedade Options
protegida / pública para que uma classe derivada também possa usá-la.
Fora isso, tudo ótimo com esse novo código da minha parte. THX!
@normj deixe-me saber se / quando houver pacotes nuget atualizados. Fico feliz em fazer outro teste.
https://github.com/aws/aws-lambda-dotnet/issues/544#issuecomment -567780775
^ É porque não usar a caixa do camelo quebra o API Gateway?
Cos Pascal funciona bem se lambda está em ALB, mas não funciona em API Gateway, essa inconsistência é confusa. Como isso funcionava antes da mudança para system.text?
Esta é uma mudança significativa; A interface não é compatível. Devido à falta de testes de integração e / ou revisão da comunidade de candidatos a lançamento, essa violação do princípio de segregação de interface foi perdida. Quanto mais tempo isso ficar sem solução, maior será o custo e o desperdício de horas de trabalho que isso causará aos clientes da AWS, resultando em impacto na reputação da AWS.
Recomendo que você marque esta versão como interrompida e desencoraje a migração para o 3.1 para todos os desenvolvedores até que uma correção seja acordada.
Além disso, também recomendo que qualquer correção seja discutida e totalmente testada pela comunidade para reduzir a probabilidade de agravar ainda mais o problema
@lukebrowell O trabalho para o serializador foi feito em público com o PR enviado em janeiro. https://github.com/aws/aws-lambda-dotnet/pull/568 O PR anexou um pacote pré-construído para teste que poderia ter sido feito com tempos de execução Lambda personalizados.
Estamos discutindo a correção aqui, juntamente com o PR e agradeço comentários sobre a correção proposta https://github.com/aws/aws-lambda-dotnet/pull/636
Eu concordo que essa é uma alteração significativa e estou decepcionado com isso, mas discordo sobre a gravidade que você sugere. O problema afeta apenas as funções do Lambda que retornam respostas personalizadas, nem todas as funções do Lambda e o Amazon.Lambda.Serialization.Json existente funciona da mesma forma, então não acredito que seja justo dizer que toda a versão 3.1 do Lambda está quebrada. Mas, novamente, eu entendo a frustração e sinto muito que o bug tenha escapado.
Espero promover as mudanças no PR no início da próxima semana, a menos que algum feedback significativo sobre a mudança venha a atrasar o lançamento.
@bjorg O PR foi atualizado com um link para preview2 dos pacotes pré-construídos. https://normj-packages.s3.us-west-2.amazonaws.com/rework-serialization-preview2.zip
@normj Percebo que a comunidade é parcialmente responsável aqui com relação à omissão desses problemas, pois (nós) pressionamos para liberar / dar suporte ao runtime .netcore 3.1 como uma imagem lambda oficial e não relatamos isso ou demos feedback. IMHO, embora eu entenda sua opinião com relação aos comentários de @lukebrowell e sugiro que uma unidade de trabalho seja iniciada (com envolvimento total da comunidade) para abrir a discussão sobre recursos / design da biblioteca de funções / serviços lambda aspnetcore com o objetivo de resolver quaisquer deficiências e / ou bugs que tenham sido identificados em uma mansão que ajude o desenvolvimento a avançar, já que este pacote parece um trabalho um pouco apressado TBH.
Eu adoraria ver uma comunidade mais forte. Tenho andado pelo awsdevelopers.slack.com, mas o canal #dotnet é um pouco quieto. Existe outro lugar onde o pessoal do Lambda .NET Core está se reunindo?
@bjorg vou entrar;) vejo você lá (virtualmente)
@bjorg é possível obter um convite?
Obtendo um link de convite dos moderadores. Vou postar aqui.
É possível manter esse assunto em questão?
Concordo, vamos manter isso no tópico. Eu criei um problema da comunidade # 647 sobre como entrar em contato comigo para adicioná-lo ao grupo AWS slack.
Sim, agradeço sugestões sobre como configurar melhor a comunicação da comunidade e onde posso fazer melhor sobre minha própria comunicação e como posso me envolver mais.
_preview2_ parece bom para mim.
A versão 2.0.0 de Amazon.Lambda.Serialization.SystemTextJson já saiu com a mudança. Principalmente, atualize a classe do serializador para DefaultLambdaJsonSerializer
.
Também publiquei uma postagem no blog que contém uma seção que descreve a mudança.
https://aws.amazon.com/blogs/developer/one-month-update-to-net-core-3-1-lambda/
Comentários muito úteis
É possível manter esse assunto em questão?