From e8fe653d2b9061fc0ad275be69258a68c52b2032 Mon Sep 17 00:00:00 2001 From: Jonas Ha Date: Sat, 29 Nov 2025 13:30:08 -0500 Subject: [PATCH 1/4] refactor(abstractions): replace `Lazy` implementation with property for JSON options - Refactored `LambdaDefaultJsonOptions` from lazy initialization to a property with caching. - Improved clarity and maintainability of the code by simplifying access patterns. --- .../Options/EnvelopeOptions.cs | 67 ++++++++++--------- 1 file changed, 37 insertions(+), 30 deletions(-) diff --git a/src/AwsLambda.Host.Abstractions/Options/EnvelopeOptions.cs b/src/AwsLambda.Host.Abstractions/Options/EnvelopeOptions.cs index 0b5764a4..641c6f4d 100644 --- a/src/AwsLambda.Host.Abstractions/Options/EnvelopeOptions.cs +++ b/src/AwsLambda.Host.Abstractions/Options/EnvelopeOptions.cs @@ -16,36 +16,6 @@ namespace AwsLambda.Host.Options; /// public class EnvelopeOptions { - /// - /// Gets the default JSON serialization options that match those used by - /// . - /// - /// - /// - /// Provides AWS Lambda-specific JSON settings for deserialization. This is used for complex - /// envelope payloads such as SNS to SQS and CloudWatch Logs. - /// - /// - /// The from - /// will be added to these options during post-configuration. - /// - /// - public readonly Lazy LambdaDefaultJsonOptions = new(() => - { - var options = new JsonSerializerOptions - { - DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, - PropertyNameCaseInsensitive = true, - PropertyNamingPolicy = new AwsNamingPolicy(), - }; - options.Converters.Add(new DateTimeConverter()); - options.Converters.Add(new MemoryStreamConverter()); - options.Converters.Add(new ConstantClassConverter()); - options.Converters.Add(new ByteArrayConverter()); - - return options; - }); - /// /// Gets or sets a dictionary for storing custom extension data associated with envelope /// processing. @@ -72,6 +42,43 @@ public class EnvelopeOptions /// public JsonSerializerOptions JsonOptions { get; set; } = new(); + /// + /// Gets the default JSON serialization options that match those used by + /// . + /// + /// + /// + /// Provides AWS Lambda-specific JSON settings for deserialization. This is used for complex + /// envelope payloads such as SNS to SQS and CloudWatch Logs. + /// + /// + /// The from + /// will be added to these options during post-configuration. + /// + /// + public JsonSerializerOptions LambdaDefaultJsonOptions + { + get + { + if (field is null) + { + field = new JsonSerializerOptions + { + DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, + PropertyNameCaseInsensitive = true, + PropertyNamingPolicy = new AwsNamingPolicy(), + }; + field.Converters.Add(new DateTimeConverter()); + field.Converters.Add(new MemoryStreamConverter()); + field.Converters.Add(new ConstantClassConverter()); + field.Converters.Add(new ByteArrayConverter()); + } + + return field; + } + set; + } + /// Gets or sets the XML reader settings used when deserializing Lambda event payloads. /// /// Options include DTD processing, whitespace handling, and conformance level. From 76296557589b871acb7b72aaa44c8fc62bc23ea4 Mon Sep 17 00:00:00 2001 From: Jonas Ha Date: Sat, 29 Nov 2025 13:37:42 -0500 Subject: [PATCH 2/4] fix(core): ensure TypeInfoResolver is only set when not explicitly configured - Updated `PostConfigure` logic to conditionally assign `TypeInfoResolver` if not already set. - Clarified XML documentation regarding the behavior of `TypeInfoResolver` assignment. --- src/AwsLambda.Host.Abstractions/Options/EnvelopeOptions.cs | 5 +++-- .../Core/Options/EnvelopeOptionsPostConfiguration.cs | 4 +--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/AwsLambda.Host.Abstractions/Options/EnvelopeOptions.cs b/src/AwsLambda.Host.Abstractions/Options/EnvelopeOptions.cs index 641c6f4d..8dc0cc2e 100644 --- a/src/AwsLambda.Host.Abstractions/Options/EnvelopeOptions.cs +++ b/src/AwsLambda.Host.Abstractions/Options/EnvelopeOptions.cs @@ -52,8 +52,9 @@ public class EnvelopeOptions /// envelope payloads such as SNS to SQS and CloudWatch Logs. /// /// - /// The from - /// will be added to these options during post-configuration. + /// During post-configuration, the from + /// will be copied to these options if TypeInfoResolver has + /// not been explicitly configured. /// /// public JsonSerializerOptions LambdaDefaultJsonOptions diff --git a/src/AwsLambda.Host/Core/Options/EnvelopeOptionsPostConfiguration.cs b/src/AwsLambda.Host/Core/Options/EnvelopeOptionsPostConfiguration.cs index b7534d24..5a85809d 100644 --- a/src/AwsLambda.Host/Core/Options/EnvelopeOptionsPostConfiguration.cs +++ b/src/AwsLambda.Host/Core/Options/EnvelopeOptionsPostConfiguration.cs @@ -5,7 +5,5 @@ namespace AwsLambda.Host.Options; internal class EnvelopeOptionsPostConfiguration : IPostConfigureOptions { public void PostConfigure(string? name, EnvelopeOptions options) => - options.LambdaDefaultJsonOptions.Value.TypeInfoResolver = options - .JsonOptions - .TypeInfoResolver; + options.LambdaDefaultJsonOptions.TypeInfoResolver ??= options.JsonOptions.TypeInfoResolver; } From cc2040264d3ed36728db17903d11d5b855a04753 Mon Sep 17 00:00:00 2001 From: Jonas Ha Date: Sat, 29 Nov 2025 13:39:06 -0500 Subject: [PATCH 3/4] refactor(envelopes): replace lazy JSON options with direct property access - Updated `SqsSnsEnvelope` to use `LambdaDefaultJsonOptions` directly instead of `.Value`. - Updated `CloudWatchLogsEnvelopeBase` for consistent use of `LambdaDefaultJsonOptions`. --- .../CloudWatchLogsEnvelopeBase.cs | 2 +- src/Envelopes/AwsLambda.Host.Envelopes.Sqs/SqsSnsEnvelope.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Envelopes/AwsLambda.Host.Envelopes.CloudWatchLogs/CloudWatchLogsEnvelopeBase.cs b/src/Envelopes/AwsLambda.Host.Envelopes.CloudWatchLogs/CloudWatchLogsEnvelopeBase.cs index 3627ff18..3904c139 100644 --- a/src/Envelopes/AwsLambda.Host.Envelopes.CloudWatchLogs/CloudWatchLogsEnvelopeBase.cs +++ b/src/Envelopes/AwsLambda.Host.Envelopes.CloudWatchLogs/CloudWatchLogsEnvelopeBase.cs @@ -25,7 +25,7 @@ public virtual void ExtractPayload(EnvelopeOptions options) AwslogsContent = JsonSerializer.Deserialize( decodedData, - options.LambdaDefaultJsonOptions.Value + options.LambdaDefaultJsonOptions ) ?? throw new InvalidOperationException("Invalid CloudWatch Logs data."); } diff --git a/src/Envelopes/AwsLambda.Host.Envelopes.Sqs/SqsSnsEnvelope.cs b/src/Envelopes/AwsLambda.Host.Envelopes.Sqs/SqsSnsEnvelope.cs index b16a3ebe..ffa88e72 100644 --- a/src/Envelopes/AwsLambda.Host.Envelopes.Sqs/SqsSnsEnvelope.cs +++ b/src/Envelopes/AwsLambda.Host.Envelopes.Sqs/SqsSnsEnvelope.cs @@ -39,7 +39,7 @@ public override void ExtractPayload(EnvelopeOptions options) { record.BodyContent = JsonSerializer.Deserialize.SnsMessageEnvelope>( record.Body, - options.LambdaDefaultJsonOptions.Value + options.LambdaDefaultJsonOptions ); record.BodyContent!.MessageContent = JsonSerializer.Deserialize( From f1c631d51c8592adaf2b15fb3a2202695b9d5038 Mon Sep 17 00:00:00 2001 From: Jonas Ha Date: Sat, 29 Nov 2025 13:40:07 -0500 Subject: [PATCH 4/4] refactor(tests): remove unnecessary use of `.Value` for JSON options - Updated `CloudWatchLogsEnvelopeTests` to access `LambdaDefaultJsonOptions` directly. - Simplified `JsonSerializer.Serialize` calls for improved readability and maintainability. --- .../CloudWatchLogsEnvelopeTests.cs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/tests/AwsLambda.Host.Envelopes.UnitTests/CloudWatchLogsEnvelopeTests.cs b/tests/AwsLambda.Host.Envelopes.UnitTests/CloudWatchLogsEnvelopeTests.cs index 21b4b383..5c1237f8 100644 --- a/tests/AwsLambda.Host.Envelopes.UnitTests/CloudWatchLogsEnvelopeTests.cs +++ b/tests/AwsLambda.Host.Envelopes.UnitTests/CloudWatchLogsEnvelopeTests.cs @@ -429,10 +429,7 @@ object awslogsData { var envelopeOptions = new EnvelopeOptions(); - var json = JsonSerializer.Serialize( - awslogsData, - envelopeOptions.LambdaDefaultJsonOptions.Value - ); + var json = JsonSerializer.Serialize(awslogsData, envelopeOptions.LambdaDefaultJsonOptions); var jsonBytes = Encoding.UTF8.GetBytes(json); using var outputStream = new MemoryStream(); @@ -534,10 +531,7 @@ private CloudWatchLogsEnvelope CreateNonGenericEnvelopeWithAwslogsData(object aw { var envelopeOptions = new EnvelopeOptions(); - var json = JsonSerializer.Serialize( - awslogsData, - envelopeOptions.LambdaDefaultJsonOptions.Value - ); + var json = JsonSerializer.Serialize(awslogsData, envelopeOptions.LambdaDefaultJsonOptions); var jsonBytes = Encoding.UTF8.GetBytes(json); using var outputStream = new MemoryStream();