Aws-lambda-dotnet: Amazon.Lambda.Serialization.SystemTextJson.LambdaJsonSerializer использует другой регистр свойств, чем Amazon.Lambda.Serialization.Json.JsonSerializer

Созданный на 15 апр. 2020  ·  43Комментарии  ·  Источник: aws/aws-lambda-dotnet

Похоже, что поведение регистра по умолчанию изменилось между Amazon.Lambda.Serialization.Json.JsonSerializer и Amazon.Lambda.Serialization.SystemTextJson.LambdaJsonSerializer .

Вот пример кода, чтобы проверить разницу:

// 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());
}

Приведенный выше код дает следующий результат:

Amazon.Lambda.Serialization.Json.JsonSerializer: {"Foo":"Hello world!"}
Amazon.Lambda.Serialization.SystemTextJson.LambdaJsonSerializer: {"foo":"Hello world!"}
System.Text.Json.JsonSerializer: {"Foo":"Hello world!"}

Самый полезный комментарий

Можно ли оставить этот вопрос в теме?

Все 43 Комментарий

Согласился, я не должен был переключать корпус между двумя библиотеками. Я думаю, что нам не хватает тестов для пользовательских запросов и ответов, поскольку теперь тесты в основном сосредоточены на событиях AWS.

Теперь, когда это сделано, изменение поведения по умолчанию действительно невозможно. Я предлагаю добавить новый конструктор, который принимает перечисление для стиля корпуса, чтобы вы могли объявить корпус, который хотите использовать. Затем я мог бы обновить шаблоны, чтобы использовать новый конструктор. Как вы относитесь к этой работе?

Я не знаю, в чем заключалась идея. Я понимаю, что вы не хотите ломать людей, которые, возможно, стали зависимыми. Похоже, ошибкой было полагать, что AWS согласованно именует поля JSON (например, AWSNamingPolicy ). Это не. Некоторые сервисы используют Pascal-casing, например CloudFormation:
https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/crpg-ref-responses.html

Автоматическая смена корпуса и несоблюдение поведения по умолчанию System.Text.Json - это фатальный недостаток, ИМХО. Может быть, стоит выпустить Amazon.Lambda.Serialization.SystemTextJson.LambdaJsonSerializerV2 и заморозить старую.

Чтобы уточнить, поскольку я не знаком с тем, как это работает, объявление атрибута сборки используется только для десериализации, правильно?

[assembly: LambdaSerializer(typeof(Amazon.Lambda.SystemTextJson.LambdaJsonSerializer))]

Однако нужно ли это вообще, если я использую эту подпись обработчика?

Task<Stream> FunctionHandlerAsync(Stream stream, ILambdaContext context)

Что произойдет, если нет объявления LambdaSerializerAttribute для метода сборки или точки входа?

@normj опция может заключаться в добавлении атрибутов для явного имени свойств json и, следовательно, соблюдения именования независимо от регистра

Я согласен с этим предложением - это утомительная разовая работа, чтобы добавить их, но тогда они всегда верны.

@normj ИМХО, это проблема реализации, которая требует / должна быть

@ 3GDXC Я согласен, что это ошибка реализации. Просто думаю о решении. В настоящее время в пакете есть один сериализатор под названием LambdaJsonSerializer . Что, если мы добавим сериализаторы PascalCaseLambdaJsonSerializer и CamelCaseLambdaJsonSerializer которые являются продолжением LambdaJsonSerializer . Я мог бы изменить шаблоны, чтобы использовать PascalCaseLambdaJsonSerializer чтобы сохранить существующее поведение. Это своего рода более явная версия предложения @bjorg о наличии LambdaJsonSerializerV2.

@normj IMHO было бы лучше, чтобы избежать путаницы, добавив атрибуты JsonPropertyName в сообщения, чтобы независимо от конфигурации / параметров сериализатора полученный Json придерживался именования атрибутов.

Я полностью понимаю, почему вы не хотите вносить еще одно критическое изменение (с исправлением) в течение нескольких дней после выпуска поддержки .NET 3.1; и если бы у нас (по-королевски) было несколько проблем UP-FOR-GRABS, без модульного / регрессионного тестирования, сообщество могло бы помочь с ними, чтобы реализация развивалась и тестировалась до выпуска.

Рад помочь, если / когда необходимо, просто скажите слово.

отличная работа, приятно видеть, как растет поддержка aws lamba и .net core

@ 3GDXC Имейте в виду, что https://github.com/aws/aws-lambda-dotnet/blob/master/Libraries/src/Amazon.Lambda.APIGatewayEvents/APIGatewayProxyResponse. cs # L18

Проблема заключается в объектах ответа, которые создают другие люди, где я не могу контролировать, используют ли они атрибут JsonPropertyName или нет.

@normj хорошее замечание; может быть совет также должен включать ВСЕГДА использовать атрибуты JsonPropertyName для обеспечения явного именования ваших свойств и / или контрактов данных (лучшие практики)

@normj альтернативой может быть абстрагирование JsonSerializerOptions в класс LambdaSerializerOptions и добавление параметров в качестве параметра конструктора в атрибуте, чтобы сериализатор мог иметь настраиваемые параметры, которые разработчик может переопределить на уровне сборки / метода

Как насчет того, чтобы пометить это как регресс и исправить как критическое изменение, вместо того, чтобы причинять еще больший вред? Я называю это _harm_, потому что LambdaJsonSerializer , основанный на System.Text.Json , не соблюдает поведение по умолчанию при сериализации свойств. Конечно, использование [JsonPropertyName] исправляет это, но требовать от всех действий для противодействия нежелательному поведению кажется жестким.

Сколько людей будут продолжать сталкиваться с этим как _?!?!? _ Момент, когда они примут LambdaJsonSerializer качестве своего стандартного сериализатора?

Привет, я столкнулся с этой проблемой в Step Functions после переключения лямбда-задач на .Net 3.1 + новый сериализатор. Это сеет хаос, потому что выходные данные теперь находятся в верблюжьем кейсе, поэтому следующая форма конечного автомата пытается оценить новый JSON с использованием языка состояний Amazon и выдает исключение Step Function.

На данный момент существует неуклюжий обходной путь. Установив LAMBDA_NET_SERIALIZER_DEBUG=true в переменной среды, _.options никогда не устанавливается в сериализаторе, что приводит к возврату регистра без изменений. Я не уверен, что это приведет к другим последствиям, кроме добавления дополнительного JSON в журналы Cloudwatch.
https://github.com/aws/aws-lambda-dotnet/blob/master/Libraries/src/Amazon.Lambda.Serialization.SystemTextJson/LambdaJsonSerializer.cs#L69 -L90

ИМО, было бы сложно украсить все наши модели украшением [JsonPropertyName] поскольку наши модели похоронены в ряде библиотек nuget. В идеале я бы хотел, чтобы поведение по умолчанию вернулось к исходному PascalCasing, как и раньше, но я вполне могу использовать явное PascalCaseLambdaJsonSerializer с лямбдами, когда оно вызывается в нашем проекте Step Function.

Благодаря!

Я почти уверен, что это неуклюжий обходной путь - ошибка.

Хорошая точка зрения на структуры данных, определенные вышестоящими сборками.

Я не знаю, какой побочный эффект это будет иметь для других вещей без атрибутов [JsonPropertyName] , но с помощью конструктора LambdaJsonSerializer который позволяет настраивать сериализатор JSON, можно вернуться к поведению PascalCase по умолчанию с помощью установка JsonSerializerOptions.PropertyNamingPolicy на null .

Ссылка на проблему № 628, поскольку она связана с этим обсуждением.

Я думаю, это связано.

Посмотрев на APIGatewayProxyRequest.cs , я заметил, что там нет аннотаций [JsonPropertyName] . Единственная причина, по которой это работает, заключается в том, что а) LambdaJsonSerializer умолчанию использует десериализацию без учета регистра и б) LambdaJsonSerializer использует верблюжий регистр при сериализации.

Я вижу, как это сэкономило много часов на аннотировании всех классов запроса / ответа в различных вспомогательных сборках, но это означает, что, когда мы используем вспомогательные сборки, мы должны использовать LambdaJsonSerializer в наших функциях.

Оглядываясь назад, не имеет ли смысл помещать аннотацию [LambdaSerializer(typeof(Amazon.Lambda.Serialization.Json.JsonSerializer))] в класс POCO, используемый обработчиком функции, а не в сам класс функции? Похоже, что в конечном итоге функция должна использовать сериализатор, соответствующий классам запроса / ответа.

@bjorg IMO POCO - это неправильное место для метаданных атрибутов о сериализации, которая должна использоваться; POCO должен быть связан только с его областью, т.е. атрибутами проверки модели и типом / наименованием свойства; при сериализации следует учитывать / использовать эти аннотации модели.

IMHO атрибут LambdaSerializer следует изменить, чтобы принять тип сериализации, например. Amazon.Lambda.Serialization.Json.JsonSerializer с дополнительными параметрами сериализации; если опция не указана, будут использоваться стандартные и совместимые настройки.

Но POCO необходимо аннотировать с помощью правильных атрибутов сериализатора: [JsonProperty] для Newtonsoft и [JsonPropertyName] для System.Text.Json. Следовательно, POCO привязан к сериализатору.

Похоже, что [DataMember] будет поддерживаться как Newtonsoft.Json и System.Text.Json . Однако для последнего не раньше .NET 5. :(
https://github.com/dotnet/runtime/issues/29975

А пока решением было бы аннотировать все POCO с помощью [DataMember] и [JsonPropertyName] . Оба атрибута определены в .NET Core 3.1 и поэтому не требуют дополнительных внешних зависимостей.

Разве это не обеспечило бы последовательную сериализацию / десериализацию для всех классов, по крайней мере, для имен свойств? Конвертеры должны быть зарегистрированы реализациями ILambdaSerialize .

Связанный выпуск закрыт. Насколько я понимаю из беглого чтения этого потока, они не собираются его поддерживать: https://github.com/dotnet/runtime/issues/29975#issuecomment -609985802

Ага. Я неправильно понял. Я увидел ссылку 5.0 и сделал неправильный вывод.

Я опубликовал PR https://github.com/aws/aws-lambda-dotnet/pull/636, чтобы решить эту проблему. Я был бы признателен за отзывы или, еще лучше, загрузите предварительную сборку по ссылке в PR и помогу убедиться, что изменение работает для вас.

Во-первых, спасибо, что так быстро с этим справились. Извини, что испортил тебе субботу.

На первый взгляд выглядит неплохо. В настоящее время я пытаюсь удалить все ссылки на Newtonsoft.Json и, к сожалению, я не в состоянии проверить исправление. На данный момент я просто скопировал проблемный класс сериализатора и удалил некорректную инструкцию. Надеюсь, к завтрашнему дню EOD я смогу протестировать это изменение в своей ветке разработки.

Первое, что приходит в голову, - это потенциально отсутствие аннотаций. Были ли какие-либо структуры данных ответа, которые не использовали [DataMember] и вместо этого полагались на неявный верблюжий регистр?

@bjorg Не беспокойтесь. После недели встреч, написания документов и помощи детям в школе, было очень приятно провести несколько минут в тишине и по субботам заняться кодированием.

У нас была возможность пропустить аннотацию [DataMember] с сериализатором Newtonsoft. Я не слишком беспокоюсь об этом, потому что для известных типов у нас есть тест на это. В этом случае в моем пробеле отсутствовали тесты на пользовательские ответы.

Можно ли выпустить -rc1 ? Альтернатива, AFAIK, для меня - в противном случае взломать мои файлы _.csproj_ с включенными правильными константами компиляции. Есть другой способ?

@bjorg В PR есть ссылка на zip-файл, содержащий предварительно созданные пакеты NuGet, можете ли вы настроить локальный источник NuGet и поместить туда пакеты?

Узнал сегодня кое-что новое: как иметь местную ленту. В .NET Core оказалось очень просто (см. Статью SO ).

Моя самая важная обратная связь - предоставить _options как защищенное / общедоступное свойство Options чтобы производный класс также мог его использовать.

В остальном все отлично с этим новым кодом с моей стороны. Спасибо!

@normj дайте мне знать, если / когда

https://github.com/aws/aws-lambda-dotnet/issues/544#issuecomment -567780775

^ Это потому, что отказ от верблюжьей оболочки нарушает работу шлюза API?

Cos Pascal отлично работает, если лямбда находится на ALB, но не работает на API Gateway, это несоответствие сбивает с толку. Как это работало до перехода на system.text?

Это критическое изменение; Интерфейс не соответствует требованиям. Из-за отсутствия интеграционного тестирования и / или проверки сообществом кандидатов на выпуск это нарушение принципа разделения интерфейса проскочило. Чем дольше этот вопрос будет оставаться нерешенным, тем больше будут затраты и потраченные впустую человеко-часы для клиентов AWS, что скажется на репутации AWS.

Я рекомендую вам пометить этот выпуск как неисправный и не поощрять переход на 3.1 для всех разработчиков, пока исправление не будет согласовано.
Кроме того, я также рекомендую, чтобы любое исправление было обсуждено и полностью протестировано сообществом, чтобы снизить вероятность дальнейшего усугубления проблемы.

@lukebrowell Работа над сериализатором была сделана публично, а PR был отправлен еще в январе. https://github.com/aws/aws-lambda-dotnet/pull/568 PR приложил предварительно собранный пакет для тестирования, которое можно было бы сделать с помощью пользовательских сред выполнения Lambda.

Мы обсуждаем здесь исправление вместе с PR, и я приветствую отзывы о предлагаемом исправлении https://github.com/aws/aws-lambda-dotnet/pull/636

Я согласен, что это критическое изменение, и я разочарован, что это произошло, но я не согласен с серьезностью, которую вы предлагаете. Проблема затрагивает только функции Lambda, возвращающие пользовательские ответы, не все функции Lambda и существующие Amazon.Lambda.Serialization.Json работают одинаково, поэтому я не считаю справедливым говорить, что вся версия 3.1 Lambda нарушена. Но опять же, я понимаю разочарование, и мне очень жаль, что ошибка ускользнула.

Я надеюсь продвинуть изменения в PR в начале следующей недели, если не поступит какой-либо существенный отзыв об изменении, который приведет к задержке выпуска.

@bjorg В PR добавлена ​​ссылка на предварительный просмотр2 готовых пакетов. https://normj-packages.s3.us-west-2.amazonaws.com/rework-serialization-preview2.zip

@normj Я понимаю, что сообщество частично несет ответственность за отсутствие этих проблем, поскольку (мы) оказали давление, чтобы выпустить / поддержать среду выполнения .netcore 3.1 в качестве официального лямбда-образа, и не сообщили об этом и не дали отзывов. ИМХО, хотя я понимаю ваше мнение в отношении комментариев @lukebrowell, я частично согласен с @lukebrowell и предлагаю

Я хотел бы видеть более сильное сообщество. Я тусил на awsdevelopers.slack.com, но канал #dotnet немного тихий. Есть ли еще одно место, где собираются ребята из Lambda .NET Core?

@bjorg Я присоединюсь;)

@bjorg можно ли получить

Получение пригласительной ссылки от модераторов. Выложу здесь.

Можно ли оставить этот вопрос в теме?

Согласен, будем держать это в теме. Я создал проблему сообщества № 647 о том, как связаться со мной, чтобы добавить вас в группу AWS Slack.

Да, я приветствую предложения о том, как лучше настроить общение с сообществом и где я могу лучше заниматься своим собственным общением и как я могу принять более активное участие.

_preview2_ мне нравится.

Версия 2.0.0 Amazon.Lambda.Serialization.SystemTextJson вышла с изменением. Главное убрать это обновить класс сериализатора до DefaultLambdaJsonSerializer .

Я также опубликовал сообщение в блоге, в котором есть раздел, описывающий изменение.
https://aws.amazon.com/blogs/developer/one-month-update-to-net-core-3-1-lambda/

Была ли эта страница полезной?
0 / 5 - 0 рейтинги