Похоже, что поведение регистра по умолчанию изменилось между 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!"}
Согласился, я не должен был переключать корпус между двумя библиотеками. Я думаю, что нам не хватает тестов для пользовательских запросов и ответов, поскольку теперь тесты в основном сосредоточены на событиях 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/
Самый полезный комментарий
Можно ли оставить этот вопрос в теме?