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
+
+
+
+
+
+
+
+
+
+
+
+
+