Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rework Amazon.Lambda.Serialization.SystemTextJson #636

Merged
merged 4 commits into from
Apr 28, 2020
Merged

Conversation

normj
Copy link
Member

@normj normj commented Apr 19, 2020

Issue #, if available:
#624
#628

Description of changes:
Amazon.Lambda.Serialization.SystemTextJson unintentionally used camel casing when serializing response objects to JSON. This is different then both Amazon.Lambda.Serialization.Json and the default behavior of System.Text.Json.

Fixing the behavior in LambdaJsonSerializer would be runtime breaking behavior and there is no metrics to know how impactful the change would be path. Instead I took the safer approach and created a new serializer called DefaultLambdaJsonSerializer that would use System.Text.Json's default casing behavior which is to use the casing matching the properties of the .NET property. For developers that did want the camel casing behavior there is also a new serializer called CamelCaseLambdaJsonSerializer.

LambdaJsonSerializer has been marked as Obsolete with no plans to change it going forward.

Here is a link to a zip file of a preview build of all of the packages for anybody that would like to test the change. https://normj-packages.s3.us-west-2.amazonaws.com/rework-serialization-preview2.zip

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.

IgnoreNullValues = true,
PropertyNameCaseInsensitive = true,
PropertyNamingPolicy = new AwsNamingPolicy()
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A bit more modern notation, but functionality the same:

            _options = new JsonSerializerOptions()
            {
                IgnoreNullValues = true,
                PropertyNameCaseInsensitive = true,
                PropertyNamingPolicy = new AwsNamingPolicy(),
                Converters = 
                {
                    new DateTimeConverter(),
                    new MemoryStreamConverter(),
                    new ConstantClassConverter()
                }
            };

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

_options = new JsonSerializerOptions()
{
IgnoreNullValues = true,
PropertyNameCaseInsensitive = true,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is PropertyNameCaseInsensitive = true still needed?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Going from JSON to .NET Object you would still need it.

/// Amazon.Lambda.Serialization.SystemTextJson's default settings have been applied.
/// </summary>
/// <param name="customizer"></param>
public DefaultLambdaJsonSerializer(Action<JsonSerializerOptions> customizer)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An alternative would be to make _options protected so it can be accessed by a derived class.

If I'm not mistaken, the only way to customize the base class is by constructor since it's the AWS Lambda Runtime for .NET Core that instantiates this class, correct?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And by making protected, I meant adding a property. For example,

protected JsonSerializerOptions SerializerOptions => _options;

Copy link
Contributor

@bjorg bjorg Apr 20, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I need the _options object so I can add my own Serialize(Stream,Type) method to the serializer (needed by my middleware).

I was hoping I could use the Action<> callback in the constructor to store a reference, but alas, that's not legal in C#.

// does not work, because the lambda function has no 'this' context in the 'base' invocation
public LambdaJsonSerializer() : base(options => _myOptions = options) { }

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I turned the options into a protected property;

<AssemblyName>Amazon.Lambda.ApplicationLoadBalancerEvents</AssemblyName>
<PackageId>Amazon.Lambda.ApplicationLoadBalancerEvents</PackageId>
<PackageTags>AWS;Amazon;Lambda</PackageTags>
</PropertyGroup>

<PropertyGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
<DefineConstants>NETSTANDARD_2_0</DefineConstants>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not use the built-in NETSTANDARD_20 and NETCOREAPP_31 hash-defines?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1. Although it looks like they are NETSTANDARD2_0 and NETCOREAPP3_1 - https://docs.microsoft.com/en-us/dotnet/core/tutorials/libraries

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, I didn't realize there were built in symbols. Updated PR to use them.

<AssemblyName>Amazon.Lambda.ApplicationLoadBalancerEvents</AssemblyName>
<PackageId>Amazon.Lambda.ApplicationLoadBalancerEvents</PackageId>
<PackageTags>AWS;Amazon;Lambda</PackageTags>
</PropertyGroup>

<PropertyGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
<DefineConstants>NETSTANDARD_2_0</DefineConstants>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1. Although it looks like they are NETSTANDARD2_0 and NETCOREAPP3_1 - https://docs.microsoft.com/en-us/dotnet/core/tutorials/libraries


/// <summary>
/// Creates the AWS Naming policy. If the name matches one of the reserved AWS words it will return the
/// appropriate mapping for it. Otherwise the name will be return as is like the JsonDefaultNamingPolicy.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

return => returned or remove "be" before return.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Comment on lines 51 to 60
if (_fallbackNamingPolicy == null)
{
// If no naming policy given then just return the name like the JsonDefaultNamingPolicy policy.
// https://github.com/dotnet/runtime/blob/master/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonDefaultNamingPolicy.cs
return name;
}
else
{
return _fallbackNamingPolicy.ConvertName(name);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: if .ConvertName(name) can't be null then you could do:

return __fallbackNamingPolicy?.ConvertName(name) ?? name;

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Comment on lines 48 to 51
if (string.Equals(Environment.GetEnvironmentVariable(DEBUG_ENVIRONMENT_VARIABLE_NAME), "true", StringComparison.OrdinalIgnoreCase))
{
this._debug = true;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: should be ok to do this...

this._debug = string.Equals(Environment.GetEnvironmentVariable(DEBUG_ENVIRONMENT_VARIABLE_NAME), "true", StringComparison.OrdinalIgnoreCase);

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

@normj normj merged commit bfb2cbb into dev Apr 28, 2020
@normj
Copy link
Member Author

normj commented Apr 28, 2020

I have merged into dev. I'll post back when the change has been published.

@normj
Copy link
Member Author

normj commented Apr 29, 2020

Version 2.0.0 went with this PR

@normj normj deleted the rework-serialization branch October 7, 2021 03:25
@normj normj restored the rework-serialization branch October 7, 2021 03:25
@normj normj deleted the rework-serialization branch October 7, 2021 03:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants