diff --git a/.editorconfig b/.editorconfig index 14f699d3..b9761641 100644 --- a/.editorconfig +++ b/.editorconfig @@ -14,6 +14,7 @@ trim_trailing_whitespace = true [*.xml] indent_size = 4 +max_line_length = 120 [*HostFactoryResolver.cs] ij_formatter_enabled = false diff --git a/.github/workflows/main-build.yaml b/.github/workflows/main-build.yaml index fc74e99c..15f8e3cf 100644 --- a/.github/workflows/main-build.yaml +++ b/.github/workflows/main-build.yaml @@ -68,7 +68,7 @@ jobs: mkdir -p ~/.sonar/scanner dotnet tool update dotnet-sonarscanner --tool-path ~/.sonar/scanner - - name: Build and analyze with SonarQube + - name: Start SonarQube env: SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} run: | @@ -78,12 +78,21 @@ jobs: /d:sonar.exclusions="**/bin/**,**/obj/**,tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/**,**/coverage/**,**/.nuget/**,**/packages/**,src/MinimalLambda.Testing/HostFactoryResolver.cs" \ /d:sonar.coverage.exclusions="**/*" \ /d:sonar.token="$SONAR_TOKEN" - dotnet build --no-restore --configuration Release /p:TreatWarningsAsErrors=true - ~/.sonar/scanner/dotnet-sonarscanner end /d:sonar.token="$SONAR_TOKEN" + + - name: Build + run: dotnet build --no-restore --configuration Release /p:TreatWarningsAsErrors=true - name: Run tests run: dotnet test --no-build --configuration Release --verbosity normal --collect:"XPlat Code Coverage" --results-directory ./coverage + - name: Stop SonarQube + env: + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} + run: ~/.sonar/scanner/dotnet-sonarscanner end /d:sonar.token="$SONAR_TOKEN" + + - name: Validate AOT Compatability + run: task build:aot-check + - name: Upload coverage reports uses: codecov/codecov-action@v5 with: diff --git a/.github/workflows/pr-build.yaml b/.github/workflows/pr-build.yaml index 1d52560c..1dc945b3 100644 --- a/.github/workflows/pr-build.yaml +++ b/.github/workflows/pr-build.yaml @@ -114,6 +114,9 @@ jobs: SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} run: ~/.sonar/scanner/dotnet-sonarscanner end /d:sonar.token="$SONAR_TOKEN" + - name: Validate AOT Compatability + run: task build:aot-check + - name: Upload coverage reports uses: codecov/codecov-action@v5 with: diff --git a/Directory.Build.props b/Directory.Build.props index a29c3c50..8bc5ba5a 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -23,4 +23,13 @@ runtime; build; native; contentfiles; analyzers; buildtransitive + + true + true + true + + + + true + diff --git a/MinimalLambda.sln b/MinimalLambda.sln index d466b293..1143161b 100644 --- a/MinimalLambda.sln +++ b/MinimalLambda.sln @@ -93,6 +93,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MinimalLambda.Envelopes", " EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MinimalLambda.Example.ClassMiddleware", "examples\MinimalLambda.Example.ClassMiddleware\MinimalLambda.Example.ClassMiddleware.csproj", "{69785FC6-B746-4104-8157-1618B80B0A4C}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AotCompatibility.TestApp", "src\AotCompatibility.TestApp\AotCompatibility.TestApp.csproj", "{A8B77486-5A06-4A02-B1F0-EB8E2669394F}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -463,6 +465,18 @@ Global {69785FC6-B746-4104-8157-1618B80B0A4C}.Release|x64.Build.0 = Release|Any CPU {69785FC6-B746-4104-8157-1618B80B0A4C}.Release|x86.ActiveCfg = Release|Any CPU {69785FC6-B746-4104-8157-1618B80B0A4C}.Release|x86.Build.0 = Release|Any CPU + {A8B77486-5A06-4A02-B1F0-EB8E2669394F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A8B77486-5A06-4A02-B1F0-EB8E2669394F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A8B77486-5A06-4A02-B1F0-EB8E2669394F}.Debug|x64.ActiveCfg = Debug|Any CPU + {A8B77486-5A06-4A02-B1F0-EB8E2669394F}.Debug|x64.Build.0 = Debug|Any CPU + {A8B77486-5A06-4A02-B1F0-EB8E2669394F}.Debug|x86.ActiveCfg = Debug|Any CPU + {A8B77486-5A06-4A02-B1F0-EB8E2669394F}.Debug|x86.Build.0 = Debug|Any CPU + {A8B77486-5A06-4A02-B1F0-EB8E2669394F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A8B77486-5A06-4A02-B1F0-EB8E2669394F}.Release|Any CPU.Build.0 = Release|Any CPU + {A8B77486-5A06-4A02-B1F0-EB8E2669394F}.Release|x64.ActiveCfg = Release|Any CPU + {A8B77486-5A06-4A02-B1F0-EB8E2669394F}.Release|x64.Build.0 = Release|Any CPU + {A8B77486-5A06-4A02-B1F0-EB8E2669394F}.Release|x86.ActiveCfg = Release|Any CPU + {A8B77486-5A06-4A02-B1F0-EB8E2669394F}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -501,5 +515,6 @@ Global {7E7B3004-C6C4-4A8C-8610-2A1CB61F834A} = {D9109C8A-AFA8-49C8-A19C-381500902B4D} {190CC9C7-007F-48C5-867D-03B911D53397} = {1C3C52D9-2936-4A0C-A9C8-F330F22B8359} {69785FC6-B746-4104-8157-1618B80B0A4C} = {B36A84DF-456D-A817-6EDD-3EC3E7F6E11F} + {A8B77486-5A06-4A02-B1F0-EB8E2669394F} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B} EndGlobalSection EndGlobal diff --git a/src/AotCompatibility.TestApp/AotCompatibility.TestApp.csproj b/src/AotCompatibility.TestApp/AotCompatibility.TestApp.csproj new file mode 100644 index 00000000..631b1453 --- /dev/null +++ b/src/AotCompatibility.TestApp/AotCompatibility.TestApp.csproj @@ -0,0 +1,40 @@ + + + Exe + net10.0 + preview + enable + enable + true + false + true + IL2026;IL2087;IL2091;IL3050;IL3051 + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/AotCompatibility.TestApp/Program.cs b/src/AotCompatibility.TestApp/Program.cs new file mode 100644 index 00000000..139ec4e7 --- /dev/null +++ b/src/AotCompatibility.TestApp/Program.cs @@ -0,0 +1,3 @@ +// See https://aka.ms/new-console-template for more information + +Console.WriteLine("Hello, World!"); diff --git a/src/Envelopes/MinimalLambda.Envelopes.Alb/AlbRequestEnvelope.cs b/src/Envelopes/MinimalLambda.Envelopes.Alb/AlbRequestEnvelope.cs index d6cfecac..9fbc0fe5 100644 --- a/src/Envelopes/MinimalLambda.Envelopes.Alb/AlbRequestEnvelope.cs +++ b/src/Envelopes/MinimalLambda.Envelopes.Alb/AlbRequestEnvelope.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using System.Text.Json; using MinimalLambda.Options; @@ -13,6 +14,16 @@ public sealed class AlbRequestEnvelope : AlbRequestEnvelopeBase { /// /// This implementation deserializes the request body from JSON. + [UnconditionalSuppressMessage( + "Aot", + "IL3050:RequiresDynamicCode", + Justification = "Safe when EnvelopeOptions.JsonOptions includes source-generated context for T" + )] + [UnconditionalSuppressMessage( + "Aot", + "IL2026:RequiresUnreferencedCode", + Justification = "Safe when EnvelopeOptions.JsonOptions includes source-generated context for T" + )] public override void ExtractPayload(EnvelopeOptions options) => BodyContent = JsonSerializer.Deserialize(Body, options.JsonOptions); } diff --git a/src/Envelopes/MinimalLambda.Envelopes.Alb/AlbResponseEnvelope.cs b/src/Envelopes/MinimalLambda.Envelopes.Alb/AlbResponseEnvelope.cs index cd8c1951..e6f12ad4 100644 --- a/src/Envelopes/MinimalLambda.Envelopes.Alb/AlbResponseEnvelope.cs +++ b/src/Envelopes/MinimalLambda.Envelopes.Alb/AlbResponseEnvelope.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using System.Text.Json; using MinimalLambda.Options; @@ -13,6 +14,16 @@ public sealed class AlbResponseEnvelope : AlbResponseEnvelopeBase { /// /// This implementation serializes the response body to JSON. + [UnconditionalSuppressMessage( + "Aot", + "IL3050:RequiresDynamicCode", + Justification = "Safe when EnvelopeOptions.JsonOptions includes source-generated context for T" + )] + [UnconditionalSuppressMessage( + "Aot", + "IL2026:RequiresUnreferencedCode", + Justification = "Safe when EnvelopeOptions.JsonOptions includes source-generated context for T" + )] public override void PackPayload(EnvelopeOptions options) => Body = JsonSerializer.Serialize(BodyContent, options.JsonOptions); } diff --git a/src/Envelopes/MinimalLambda.Envelopes.ApiGateway/ApiGatewayRequestEnvelope.cs b/src/Envelopes/MinimalLambda.Envelopes.ApiGateway/ApiGatewayRequestEnvelope.cs index 8b14f676..44ff6efb 100644 --- a/src/Envelopes/MinimalLambda.Envelopes.ApiGateway/ApiGatewayRequestEnvelope.cs +++ b/src/Envelopes/MinimalLambda.Envelopes.ApiGateway/ApiGatewayRequestEnvelope.cs @@ -1,4 +1,5 @@ -using System.Text.Json; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; using MinimalLambda.Options; namespace MinimalLambda.Envelopes.ApiGateway; @@ -13,6 +14,16 @@ public sealed class ApiGatewayRequestEnvelope : ApiGatewayRequestEnvelopeBase { /// /// This implementation deserializes the request body from JSON. + [UnconditionalSuppressMessage( + "Aot", + "IL3050:RequiresDynamicCode", + Justification = "Safe when EnvelopeOptions.JsonOptions includes source-generated context for T" + )] + [UnconditionalSuppressMessage( + "Aot", + "IL2026:RequiresUnreferencedCode", + Justification = "Safe when EnvelopeOptions.JsonOptions includes source-generated context for T" + )] public override void ExtractPayload(EnvelopeOptions options) => BodyContent = JsonSerializer.Deserialize(Body, options.JsonOptions); } diff --git a/src/Envelopes/MinimalLambda.Envelopes.ApiGateway/ApiGatewayResponseEnvelope.cs b/src/Envelopes/MinimalLambda.Envelopes.ApiGateway/ApiGatewayResponseEnvelope.cs index c580251d..198f3d3d 100644 --- a/src/Envelopes/MinimalLambda.Envelopes.ApiGateway/ApiGatewayResponseEnvelope.cs +++ b/src/Envelopes/MinimalLambda.Envelopes.ApiGateway/ApiGatewayResponseEnvelope.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using System.Text.Json; using MinimalLambda.Options; @@ -13,6 +14,16 @@ public sealed class ApiGatewayResponseEnvelope : ApiGatewayResponseEnvelopeBa { /// /// This implementation serializes the response body to JSON. + [UnconditionalSuppressMessage( + "Aot", + "IL3050:RequiresDynamicCode", + Justification = "Safe when EnvelopeOptions.JsonOptions includes source-generated context for T" + )] + [UnconditionalSuppressMessage( + "Aot", + "IL2026:RequiresUnreferencedCode", + Justification = "Safe when EnvelopeOptions.JsonOptions includes source-generated context for T" + )] public override void PackPayload(EnvelopeOptions options) => Body = JsonSerializer.Serialize(BodyContent, options.JsonOptions); } diff --git a/src/Envelopes/MinimalLambda.Envelopes.ApiGateway/ApiGatewayV2RequestEnvelope.cs b/src/Envelopes/MinimalLambda.Envelopes.ApiGateway/ApiGatewayV2RequestEnvelope.cs index 195a0ad3..f624ef0c 100644 --- a/src/Envelopes/MinimalLambda.Envelopes.ApiGateway/ApiGatewayV2RequestEnvelope.cs +++ b/src/Envelopes/MinimalLambda.Envelopes.ApiGateway/ApiGatewayV2RequestEnvelope.cs @@ -1,4 +1,5 @@ -using System.Text.Json; +using System.Diagnostics.CodeAnalysis; +using System.Text.Json; using MinimalLambda.Options; namespace MinimalLambda.Envelopes.ApiGateway; @@ -13,6 +14,16 @@ public sealed class ApiGatewayV2RequestEnvelope : ApiGatewayV2RequestEnvelope { /// /// This implementation deserializes the request body from JSON. + [UnconditionalSuppressMessage( + "Aot", + "IL3050:RequiresDynamicCode", + Justification = "Safe when EnvelopeOptions.JsonOptions includes source-generated context for T" + )] + [UnconditionalSuppressMessage( + "Aot", + "IL2026:RequiresUnreferencedCode", + Justification = "Safe when EnvelopeOptions.JsonOptions includes source-generated context for T" + )] public override void ExtractPayload(EnvelopeOptions options) => BodyContent = JsonSerializer.Deserialize(Body, options.JsonOptions); } diff --git a/src/Envelopes/MinimalLambda.Envelopes.ApiGateway/ApiGatewayV2ResponseEnvelope.cs b/src/Envelopes/MinimalLambda.Envelopes.ApiGateway/ApiGatewayV2ResponseEnvelope.cs index e239514e..616a8b12 100644 --- a/src/Envelopes/MinimalLambda.Envelopes.ApiGateway/ApiGatewayV2ResponseEnvelope.cs +++ b/src/Envelopes/MinimalLambda.Envelopes.ApiGateway/ApiGatewayV2ResponseEnvelope.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using System.Text.Json; using MinimalLambda.Options; @@ -13,6 +14,16 @@ public sealed class ApiGatewayV2ResponseEnvelope : ApiGatewayV2ResponseEnvelo { /// /// This implementation serializes the response body to JSON. + [UnconditionalSuppressMessage( + "Aot", + "IL3050:RequiresDynamicCode", + Justification = "Safe when EnvelopeOptions.JsonOptions includes source-generated context for T" + )] + [UnconditionalSuppressMessage( + "Aot", + "IL2026:RequiresUnreferencedCode", + Justification = "Safe when EnvelopeOptions.JsonOptions includes source-generated context for T" + )] public override void PackPayload(EnvelopeOptions options) => Body = JsonSerializer.Serialize(BodyContent, options.JsonOptions); } diff --git a/src/Envelopes/MinimalLambda.Envelopes.CloudWatchLogs/CloudWatchLogsEnvelopeBase.cs b/src/Envelopes/MinimalLambda.Envelopes.CloudWatchLogs/CloudWatchLogsEnvelopeBase.cs index 9b425d69..dc01a612 100644 --- a/src/Envelopes/MinimalLambda.Envelopes.CloudWatchLogs/CloudWatchLogsEnvelopeBase.cs +++ b/src/Envelopes/MinimalLambda.Envelopes.CloudWatchLogs/CloudWatchLogsEnvelopeBase.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using System.Text.Json; using System.Text.Json.Serialization; using Amazon.Lambda.CloudWatchLogsEvents; @@ -19,6 +20,16 @@ public abstract class CloudWatchLogsEnvelopeBase : CloudWatchLogsEvent, IRequ public AwsLogsEnvelope? AwslogsContent { get; set; } /// + [UnconditionalSuppressMessage( + "Aot", + "IL3050:RequiresDynamicCode", + Justification = "Safe when EnvelopeOptions.JsonOptions includes source-generated context for T" + )] + [UnconditionalSuppressMessage( + "Aot", + "IL2026:RequiresUnreferencedCode", + Justification = "Safe when EnvelopeOptions.JsonOptions includes source-generated context for T" + )] public virtual void ExtractPayload(EnvelopeOptions options) { var decodedData = Awslogs.DecodeData(); diff --git a/src/Envelopes/MinimalLambda.Envelopes.CloudWatchLogs/CloudWatchLogsEnvelopeT.cs b/src/Envelopes/MinimalLambda.Envelopes.CloudWatchLogs/CloudWatchLogsEnvelopeT.cs index 511ea957..df94ce42 100644 --- a/src/Envelopes/MinimalLambda.Envelopes.CloudWatchLogs/CloudWatchLogsEnvelopeT.cs +++ b/src/Envelopes/MinimalLambda.Envelopes.CloudWatchLogs/CloudWatchLogsEnvelopeT.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using System.Text.Json; using MinimalLambda.Options; @@ -26,6 +27,16 @@ public sealed class CloudWatchLogsEnvelope : CloudWatchLogsEnvelopeBase /// This implementation deserializes the base64-decoded and decompressed CloudWatch Logs data /// from JSON. /// + [UnconditionalSuppressMessage( + "Aot", + "IL3050:RequiresDynamicCode", + Justification = "Safe when EnvelopeOptions.JsonOptions includes source-generated context for T" + )] + [UnconditionalSuppressMessage( + "Aot", + "IL2026:RequiresUnreferencedCode", + Justification = "Safe when EnvelopeOptions.JsonOptions includes source-generated context for T" + )] public override void ExtractPayload(EnvelopeOptions options) { base.ExtractPayload(options); diff --git a/src/Envelopes/MinimalLambda.Envelopes.Kafka/KafkaEnvelope.cs b/src/Envelopes/MinimalLambda.Envelopes.Kafka/KafkaEnvelope.cs index f6df08b0..bf70872c 100644 --- a/src/Envelopes/MinimalLambda.Envelopes.Kafka/KafkaEnvelope.cs +++ b/src/Envelopes/MinimalLambda.Envelopes.Kafka/KafkaEnvelope.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using System.Text; using System.Text.Json; using MinimalLambda.Options; @@ -14,6 +15,16 @@ public sealed class KafkaEnvelope : KafkaEnvelopeBase { /// /// This implementation deserializes each base64-encoded value stream from JSON. + [UnconditionalSuppressMessage( + "Aot", + "IL3050:RequiresDynamicCode", + Justification = "Safe when EnvelopeOptions.JsonOptions includes source-generated context for T" + )] + [UnconditionalSuppressMessage( + "Aot", + "IL2026:RequiresUnreferencedCode", + Justification = "Safe when EnvelopeOptions.JsonOptions includes source-generated context for T" + )] public override void ExtractPayload(EnvelopeOptions options) { foreach (var topic in Records) diff --git a/src/Envelopes/MinimalLambda.Envelopes.Kinesis/KinesisEnvelope.cs b/src/Envelopes/MinimalLambda.Envelopes.Kinesis/KinesisEnvelope.cs index 6e1ede6b..7f235162 100644 --- a/src/Envelopes/MinimalLambda.Envelopes.Kinesis/KinesisEnvelope.cs +++ b/src/Envelopes/MinimalLambda.Envelopes.Kinesis/KinesisEnvelope.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using System.Text; using System.Text.Json; using MinimalLambda.Options; @@ -14,6 +15,16 @@ public sealed class KinesisEnvelope : KinesisEnvelopeBase { /// /// This implementation deserializes each base64-encoded data stream from JSON. + [UnconditionalSuppressMessage( + "Aot", + "IL3050:RequiresDynamicCode", + Justification = "Safe when EnvelopeOptions.JsonOptions includes source-generated context for T" + )] + [UnconditionalSuppressMessage( + "Aot", + "IL2026:RequiresUnreferencedCode", + Justification = "Safe when EnvelopeOptions.JsonOptions includes source-generated context for T" + )] public override void ExtractPayload(EnvelopeOptions options) { foreach (var record in Records) diff --git a/src/Envelopes/MinimalLambda.Envelopes.KinesisFirehose/KinesisFirehoseEventEnvelope.cs b/src/Envelopes/MinimalLambda.Envelopes.KinesisFirehose/KinesisFirehoseEventEnvelope.cs index ed2eaba4..6cc87cf8 100644 --- a/src/Envelopes/MinimalLambda.Envelopes.KinesisFirehose/KinesisFirehoseEventEnvelope.cs +++ b/src/Envelopes/MinimalLambda.Envelopes.KinesisFirehose/KinesisFirehoseEventEnvelope.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using System.Text.Json; using MinimalLambda.Options; @@ -13,6 +14,16 @@ public sealed class KinesisFirehoseEventEnvelope : KinesisFirehoseEventEnvelo { /// /// This implementation deserializes each base64-encoded Firehose data record from JSON. + [UnconditionalSuppressMessage( + "Aot", + "IL3050:RequiresDynamicCode", + Justification = "Safe when EnvelopeOptions.JsonOptions includes source-generated context for T" + )] + [UnconditionalSuppressMessage( + "Aot", + "IL2026:RequiresUnreferencedCode", + Justification = "Safe when EnvelopeOptions.JsonOptions includes source-generated context for T" + )] public override void ExtractPayload(EnvelopeOptions options) { foreach (var record in Records) diff --git a/src/Envelopes/MinimalLambda.Envelopes.KinesisFirehose/KinesisFirehoseResponseEnvelope.cs b/src/Envelopes/MinimalLambda.Envelopes.KinesisFirehose/KinesisFirehoseResponseEnvelope.cs index ce105648..59cf4c81 100644 --- a/src/Envelopes/MinimalLambda.Envelopes.KinesisFirehose/KinesisFirehoseResponseEnvelope.cs +++ b/src/Envelopes/MinimalLambda.Envelopes.KinesisFirehose/KinesisFirehoseResponseEnvelope.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using System.Text.Json; using MinimalLambda.Options; @@ -13,6 +14,16 @@ public sealed class KinesisFirehoseResponseEnvelope : KinesisFirehoseResponse { /// /// This implementation serializes each data content to JSON and encodes it as base64. + [UnconditionalSuppressMessage( + "Aot", + "IL3050:RequiresDynamicCode", + Justification = "Safe when EnvelopeOptions.JsonOptions includes source-generated context for T" + )] + [UnconditionalSuppressMessage( + "Aot", + "IL2026:RequiresUnreferencedCode", + Justification = "Safe when EnvelopeOptions.JsonOptions includes source-generated context for T" + )] public override void PackPayload(EnvelopeOptions options) { foreach (var record in Records) diff --git a/src/Envelopes/MinimalLambda.Envelopes.Sns/SnsEnvelope.cs b/src/Envelopes/MinimalLambda.Envelopes.Sns/SnsEnvelope.cs index 560ea277..36ecd689 100644 --- a/src/Envelopes/MinimalLambda.Envelopes.Sns/SnsEnvelope.cs +++ b/src/Envelopes/MinimalLambda.Envelopes.Sns/SnsEnvelope.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using System.Text.Json; using MinimalLambda.Options; @@ -13,6 +14,16 @@ public sealed class SnsEnvelope : SnsEnvelopeBase { /// /// This implementation deserializes each message body from JSON. + [UnconditionalSuppressMessage( + "Aot", + "IL3050:RequiresDynamicCode", + Justification = "Safe when EnvelopeOptions.JsonOptions includes source-generated context for T" + )] + [UnconditionalSuppressMessage( + "Aot", + "IL2026:RequiresUnreferencedCode", + Justification = "Safe when EnvelopeOptions.JsonOptions includes source-generated context for T" + )] public override void ExtractPayload(EnvelopeOptions options) { foreach (var record in Records) diff --git a/src/Envelopes/MinimalLambda.Envelopes.Sqs/SqsEnvelope.cs b/src/Envelopes/MinimalLambda.Envelopes.Sqs/SqsEnvelope.cs index d4087a7d..03a59ca3 100644 --- a/src/Envelopes/MinimalLambda.Envelopes.Sqs/SqsEnvelope.cs +++ b/src/Envelopes/MinimalLambda.Envelopes.Sqs/SqsEnvelope.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using System.Text.Json; using MinimalLambda.Options; @@ -13,6 +14,16 @@ public sealed class SqsEnvelope : SqsEnvelopeBase { /// /// This implementation deserializes each message body from JSON. + [UnconditionalSuppressMessage( + "Aot", + "IL3050:RequiresDynamicCode", + Justification = "Safe when EnvelopeOptions.JsonOptions includes source-generated context for T" + )] + [UnconditionalSuppressMessage( + "Aot", + "IL2026:RequiresUnreferencedCode", + Justification = "Safe when EnvelopeOptions.JsonOptions includes source-generated context for T" + )] public override void ExtractPayload(EnvelopeOptions options) { foreach (var record in Records) diff --git a/src/Envelopes/MinimalLambda.Envelopes.Sqs/SqsSnsEnvelope.cs b/src/Envelopes/MinimalLambda.Envelopes.Sqs/SqsSnsEnvelope.cs index 95e6bcd3..84371143 100644 --- a/src/Envelopes/MinimalLambda.Envelopes.Sqs/SqsSnsEnvelope.cs +++ b/src/Envelopes/MinimalLambda.Envelopes.Sqs/SqsSnsEnvelope.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using System.Text.Json; using MinimalLambda.Envelopes.Sns; using MinimalLambda.Options; @@ -33,6 +34,16 @@ public sealed class SqsSnsEnvelope : SqsEnvelopeBase.SnsMe /// deserialized into type using /// . /// + [UnconditionalSuppressMessage( + "Aot", + "IL3050:RequiresDynamicCode", + Justification = "Safe when EnvelopeOptions.JsonOptions includes source-generated context for T" + )] + [UnconditionalSuppressMessage( + "Aot", + "IL2026:RequiresUnreferencedCode", + Justification = "Safe when EnvelopeOptions.JsonOptions includes source-generated context for T" + )] public override void ExtractPayload(EnvelopeOptions options) { foreach (var record in Records) diff --git a/src/Envelopes/MinimalLambda.Envelopes/MinimalLambda.Envelopes.csproj b/src/Envelopes/MinimalLambda.Envelopes/MinimalLambda.Envelopes.csproj index 64cb54c8..57381f7e 100644 --- a/src/Envelopes/MinimalLambda.Envelopes/MinimalLambda.Envelopes.csproj +++ b/src/Envelopes/MinimalLambda.Envelopes/MinimalLambda.Envelopes.csproj @@ -12,6 +12,16 @@ Core components for MinimalLambda envelopes README.md + + + $(NoWarn);AD0001 + diff --git a/src/MinimalLambda.Abstractions/GlobalUsings.cs b/src/MinimalLambda.Abstractions/GlobalUsings.cs deleted file mode 100644 index 3847e967..00000000 --- a/src/MinimalLambda.Abstractions/GlobalUsings.cs +++ /dev/null @@ -1,2 +0,0 @@ -global using MinimalLambda.Builder; -global using MinimalLambda.Options; diff --git a/src/MinimalLambda.Abstractions/MinimalLambda.Abstractions.csproj b/src/MinimalLambda.Abstractions/MinimalLambda.Abstractions.csproj index a31489df..3f72e3ad 100644 --- a/src/MinimalLambda.Abstractions/MinimalLambda.Abstractions.csproj +++ b/src/MinimalLambda.Abstractions/MinimalLambda.Abstractions.csproj @@ -12,6 +12,10 @@ Core abstractions for MinimalLambda README.md + + + + diff --git a/src/MinimalLambda.OpenTelemetry/MinimalLambda.OpenTelemetry.csproj b/src/MinimalLambda.OpenTelemetry/MinimalLambda.OpenTelemetry.csproj index 24c2b1ea..875740ae 100644 --- a/src/MinimalLambda.OpenTelemetry/MinimalLambda.OpenTelemetry.csproj +++ b/src/MinimalLambda.OpenTelemetry/MinimalLambda.OpenTelemetry.csproj @@ -13,6 +13,16 @@ README.md $(InterceptorsNamespaces);MinimalLambda.Generated + + + $(NoWarn);AD0001 + diff --git a/src/MinimalLambda.SourceGenerators/MinimalLambda.SourceGenerators.csproj b/src/MinimalLambda.SourceGenerators/MinimalLambda.SourceGenerators.csproj index 7ab38e5e..5e1d51be 100644 --- a/src/MinimalLambda.SourceGenerators/MinimalLambda.SourceGenerators.csproj +++ b/src/MinimalLambda.SourceGenerators/MinimalLambda.SourceGenerators.csproj @@ -40,4 +40,7 @@ System.Runtime.CompilerServices.ModuleInitializerAttribute + + false + diff --git a/src/MinimalLambda.Testing/MinimalLambda.Testing.csproj b/src/MinimalLambda.Testing/MinimalLambda.Testing.csproj index 89be6c1b..16b4c452 100644 --- a/src/MinimalLambda.Testing/MinimalLambda.Testing.csproj +++ b/src/MinimalLambda.Testing/MinimalLambda.Testing.csproj @@ -11,6 +11,18 @@ MinimalLambda.Testing In-memory testing harness for MinimalLambda README.md + false + $(NoWarn);IL2026;IL2087;IL2091;IL3050;IL3051;IL2075 + + + + $(NoWarn);AD0001 diff --git a/src/MinimalLambda/Builder/Extensions/SerializerServiceCollectionExtensions.cs b/src/MinimalLambda/Builder/Extensions/SerializerServiceCollectionExtensions.cs index 4537d3a5..c82f9823 100644 --- a/src/MinimalLambda/Builder/Extensions/SerializerServiceCollectionExtensions.cs +++ b/src/MinimalLambda/Builder/Extensions/SerializerServiceCollectionExtensions.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using System.Text.Json.Serialization; using Amazon.Lambda.Core; using Amazon.Lambda.Serialization.SystemTextJson; @@ -30,7 +31,9 @@ public static class SerializerServiceCollectionExtensions /// /// /// - public IServiceCollection AddLambdaSerializerWithContext() + public IServiceCollection AddLambdaSerializerWithContext< + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] TContext + >() where TContext : JsonSerializerContext { ArgumentNullException.ThrowIfNull(serviceCollection); diff --git a/src/MinimalLambda/Builder/Extensions/ServiceCollectionExtensions.cs b/src/MinimalLambda/Builder/Extensions/ServiceCollectionExtensions.cs index e7beaa35..ece2123b 100644 --- a/src/MinimalLambda/Builder/Extensions/ServiceCollectionExtensions.cs +++ b/src/MinimalLambda/Builder/Extensions/ServiceCollectionExtensions.cs @@ -1,3 +1,5 @@ +using System.Diagnostics.CodeAnalysis; +using System.Runtime.CompilerServices; using Amazon.Lambda.Core; using Amazon.Lambda.Serialization.SystemTextJson; using Microsoft.Extensions.DependencyInjection.Extensions; @@ -67,11 +69,20 @@ public IServiceCollection AddLambdaHostCoreServices() /// already. /// /// The service collection for chaining. + [UnconditionalSuppressMessage( + "Aot", + "IL2026:RequiresUnreferencedCode", + Justification = "DefaultLambdaJsonSerializer is a fallback. Users can AddLambdaSerializerWithContext for AOT scenarios." + )] public IServiceCollection TryAddLambdaHostDefaultServices() { ArgumentNullException.ThrowIfNull(services); - services.TryAddSingleton(); + // We will only attempt to add ILambdaSerializer if we are not using AOT. + // This is needed for code AOT analysis. + if (RuntimeFeature.IsDynamicCodeSupported) + services.TryAddSingleton(); + services.TryAddSingleton< ILambdaCancellationFactory, DefaultLambdaCancellationFactory diff --git a/src/MinimalLambda/Builder/LambdaApplicationBuilder.cs b/src/MinimalLambda/Builder/LambdaApplicationBuilder.cs index 5f296a5f..96d018af 100644 --- a/src/MinimalLambda/Builder/LambdaApplicationBuilder.cs +++ b/src/MinimalLambda/Builder/LambdaApplicationBuilder.cs @@ -84,9 +84,9 @@ internal LambdaApplicationBuilder(LambdaApplicationOptions? settings) ConfigureContainer(serviceProviderFactory); // Configure LambdaHostSettings from appsettings.json - Services.Configure( - Configuration.GetSection(LambdaHostAppSettingsSectionName) - ); + Services + .AddOptions() + .BindConfiguration(LambdaHostAppSettingsSectionName); } // Configure LambdaHostedServiceOptions with callbacks diff --git a/src/MinimalLambda/Core/Features/DefaultEventFeature.cs b/src/MinimalLambda/Core/Features/DefaultEventFeature.cs index 48c11930..6d0bb9f8 100644 --- a/src/MinimalLambda/Core/Features/DefaultEventFeature.cs +++ b/src/MinimalLambda/Core/Features/DefaultEventFeature.cs @@ -7,19 +7,21 @@ namespace MinimalLambda; /// code. /// /// -internal class DefaultEventFeature : IEventFeature +internal class DefaultEventFeature(ILambdaSerializer? lambdaSerializer = null) : IEventFeature { - private readonly ILambdaSerializer _lambdaSerializer; + private readonly ILambdaSerializer _lambdaSerializer = + lambdaSerializer + ?? throw new ArgumentNullException( + nameof(lambdaSerializer), + "ILambdaSerializer has not been registered. In AOT scenarios you must provide an " + + "serializer by registering an ILambdaSerializer in the DI container. " + + "Use AddLambdaSerializerWithContext (registers the context for you) or " + + "manually register your serializer implementation." + ); + private T _data = default!; private bool _isDeserialized; - public DefaultEventFeature(ILambdaSerializer lambdaSerializer) - { - ArgumentNullException.ThrowIfNull(lambdaSerializer); - - _lambdaSerializer = lambdaSerializer; - } - public T GetEvent(ILambdaInvocationContext context) { if (!_isDeserialized) diff --git a/src/MinimalLambda/GlobalUsings.cs b/src/MinimalLambda/GlobalUsings.cs deleted file mode 100644 index b59a29b1..00000000 --- a/src/MinimalLambda/GlobalUsings.cs +++ /dev/null @@ -1,4 +0,0 @@ -global using MinimalLambda; -global using MinimalLambda.Builder; -global using MinimalLambda.Options; -global using MinimalLambda.Runtime; diff --git a/src/MinimalLambda/MinimalLambda.csproj b/src/MinimalLambda/MinimalLambda.csproj index 2c210d35..56dad5f3 100644 --- a/src/MinimalLambda/MinimalLambda.csproj +++ b/src/MinimalLambda/MinimalLambda.csproj @@ -13,6 +13,22 @@ README.md $(InterceptorsNamespaces);MinimalLambda.Generated + + + + + + + + + $(NoWarn);AD0001 + @@ -55,4 +71,7 @@ /> + + true + diff --git a/tasks/BuildTasks.yml b/tasks/BuildTasks.yml index 58bdc84d..4479cb65 100644 --- a/tasks/BuildTasks.yml +++ b/tasks/BuildTasks.yml @@ -53,3 +53,9 @@ tasks: - echo "🚀 Publishing" - dotnet nuget push ./nupkg/*.nupkg --source https://api.nuget.org/v3/index.json --api-key $NUGET_API_KEY --skip-duplicate - echo "✨ Published" + + aot-check: + desc: Validates the AOT compatibility of the libraries + silent: true + cmds: + - dotnet publish src/AotCompatibility.TestApp/AotCompatibility.TestApp.csproj /p:TreatWarningsAsErrors=true \ No newline at end of file diff --git a/tests/MinimalLambda.Envelopes.UnitTests/MinimalLambda.Envelopes.UnitTests.csproj b/tests/MinimalLambda.Envelopes.UnitTests/MinimalLambda.Envelopes.UnitTests.csproj index 12380ea6..3aedce4e 100644 --- a/tests/MinimalLambda.Envelopes.UnitTests/MinimalLambda.Envelopes.UnitTests.csproj +++ b/tests/MinimalLambda.Envelopes.UnitTests/MinimalLambda.Envelopes.UnitTests.csproj @@ -6,6 +6,9 @@ enable false false + false + true + $(NoWarn);IL2026;IL2087;IL2091;IL3050;IL3051 diff --git a/tests/MinimalLambda.OpenTelemetry.UnitTests/GlobalUsings.cs b/tests/MinimalLambda.OpenTelemetry.UnitTests/GlobalUsings.cs deleted file mode 100644 index 02d205b2..00000000 --- a/tests/MinimalLambda.OpenTelemetry.UnitTests/GlobalUsings.cs +++ /dev/null @@ -1,7 +0,0 @@ -global using AutoFixture; -global using AutoFixture.Xunit3; -global using AwesomeAssertions; -global using JetBrains.Annotations; -global using MinimalLambda.Builder; -global using NSubstitute; -global using Xunit; diff --git a/tests/MinimalLambda.OpenTelemetry.UnitTests/MinimalLambda.OpenTelemetry.UnitTests.csproj b/tests/MinimalLambda.OpenTelemetry.UnitTests/MinimalLambda.OpenTelemetry.UnitTests.csproj index 4d2e6a12..e8940ea9 100644 --- a/tests/MinimalLambda.OpenTelemetry.UnitTests/MinimalLambda.OpenTelemetry.UnitTests.csproj +++ b/tests/MinimalLambda.OpenTelemetry.UnitTests/MinimalLambda.OpenTelemetry.UnitTests.csproj @@ -6,7 +6,17 @@ enable false false + true + + + + + + + + + diff --git a/tests/MinimalLambda.SourceGenerators.UnitTests/MinimalLambda.SourceGenerators.UnitTests.csproj b/tests/MinimalLambda.SourceGenerators.UnitTests/MinimalLambda.SourceGenerators.UnitTests.csproj index fe7e7424..5010cb6d 100644 --- a/tests/MinimalLambda.SourceGenerators.UnitTests/MinimalLambda.SourceGenerators.UnitTests.csproj +++ b/tests/MinimalLambda.SourceGenerators.UnitTests/MinimalLambda.SourceGenerators.UnitTests.csproj @@ -6,6 +6,7 @@ enable false false + true diff --git a/tests/MinimalLambda.Testing.UnitTests/Tests/MinimalLambda.Testing.UnitTests/GlobalUsings.cs b/tests/MinimalLambda.Testing.UnitTests/Tests/MinimalLambda.Testing.UnitTests/GlobalUsings.cs deleted file mode 100644 index bd60b342..00000000 --- a/tests/MinimalLambda.Testing.UnitTests/Tests/MinimalLambda.Testing.UnitTests/GlobalUsings.cs +++ /dev/null @@ -1,4 +0,0 @@ -global using AutoFixture; -global using AwesomeAssertions; -global using NSubstitute; -global using Xunit; diff --git a/tests/MinimalLambda.Testing.UnitTests/Tests/MinimalLambda.Testing.UnitTests/MinimalLambda.Testing.UnitTests.csproj b/tests/MinimalLambda.Testing.UnitTests/Tests/MinimalLambda.Testing.UnitTests/MinimalLambda.Testing.UnitTests.csproj index 657cdaec..b9a2609d 100644 --- a/tests/MinimalLambda.Testing.UnitTests/Tests/MinimalLambda.Testing.UnitTests/MinimalLambda.Testing.UnitTests.csproj +++ b/tests/MinimalLambda.Testing.UnitTests/Tests/MinimalLambda.Testing.UnitTests/MinimalLambda.Testing.UnitTests.csproj @@ -4,7 +4,15 @@ enable enable false + true + $(NoWarn);IL2026;IL2087;IL2091;IL3050;IL3051;IL2075: + + + + + + diff --git a/tests/MinimalLambda.UnitTests/GlobalUsings.cs b/tests/MinimalLambda.UnitTests/GlobalUsings.cs deleted file mode 100644 index e413bfc8..00000000 --- a/tests/MinimalLambda.UnitTests/GlobalUsings.cs +++ /dev/null @@ -1,11 +0,0 @@ -global using Amazon.Lambda.Core; -global using AutoFixture; -global using AutoFixture.Xunit3; -global using AwesomeAssertions; -global using JetBrains.Annotations; -global using MinimalLambda; -global using MinimalLambda.Builder; -global using MinimalLambda.Options; -global using MinimalLambda.Runtime; -global using NSubstitute; -global using Xunit; diff --git a/tests/MinimalLambda.UnitTests/MinimalLambda.UnitTests.csproj b/tests/MinimalLambda.UnitTests/MinimalLambda.UnitTests.csproj index caf6b611..7cf404d3 100644 --- a/tests/MinimalLambda.UnitTests/MinimalLambda.UnitTests.csproj +++ b/tests/MinimalLambda.UnitTests/MinimalLambda.UnitTests.csproj @@ -4,9 +4,23 @@ enable enable false + true false 14 + + + + + + + + + + + + +