v9 (2/3): Native AOT support - #2183
Draft
slang25 wants to merge 8 commits into
Draft
Conversation
slang25
force-pushed
the
slang25/v9-aot
branch
3 times, most recently
from
June 23, 2026 00:00
ad407a6 to
670399d
Compare
There was a problem hiding this comment.
Pull request overview
Adds Native AOT support while making System.Text.Json the default serializer.
Changes:
- Adds source-generated serialization and AOT annotations.
- Adds an AOT round-trip test and CI job.
- Updates DI defaults, samples, and migration guidance.
Reviewed changes
Copilot reviewed 21 out of 21 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
.github/workflows/build.yml |
Runs native AOT tests in CI. |
Directory.Build.props |
Enables AOT compatibility analysis. |
JustSaying.slnx |
Adds the AOT test project. |
MIGRATION-v9.md |
Documents the serializer change. |
samples/.../ApplicationJsonContext.cs |
Defines sample serialization metadata. |
samples/.../Program.cs |
Configures source-generated serialization. |
src/...Microsoft/IServiceCollectionExtensions.cs |
Updates DI defaults and AOT annotations. |
src/...StructureMap/JustSayingRegistry.cs |
Changes StructureMap’s default serializer. |
src/...StructureMap/RegistryExtensions.cs |
Relaxes handler message constraints. |
src/JustSaying/AwsTools/MessageHandling/SnsPolicyBuilder.cs |
Uses generated policy metadata. |
src/JustSaying/AwsTools/QueueCreation/RedrivePolicy.cs |
Uses generated redrive metadata. |
src/JustSaying/Extensions/JsonSerializerOptionsExtensions.cs |
Resolves typed serialization metadata. |
src/JustSaying/Fluent/ServiceResolver/DefaultServiceResolver.cs |
Changes the fluent default serializer. |
src/JustSaying/JustSayingSerializationContext.cs |
Defines internal serialization metadata. |
src/.../NewtonsoftMessageBodySerializer\1.cs` |
Adds trimming and AOT annotations. |
src/.../NewtonsoftSerializationFactory.cs |
Marks Newtonsoft’s reflection requirements. |
src/.../SystemTextJsonMessageBodySerializer.cs |
Makes default options AOT-aware. |
src/.../SystemTextJsonMessageBodySerializer\1.cs` |
Adds source-generated serialization paths. |
tests/JustSaying.AotTest/AotRoundTripTests.cs |
Tests a native publish/handle round trip. |
tests/JustSaying.AotTest/JustSaying.AotTest.csproj |
Configures the Native AOT test app. |
tests/.../WhenUsingDefaultServiceResolver.cs |
Verifies the new serializer default. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## slang25/v9-foundation #2183 +/- ##
=========================================================
- Coverage 78.69% 78.59% -0.11%
=========================================================
Files 154 155 +1
Lines 4013 4022 +9
Branches 675 679 +4
=========================================================
+ Hits 3158 3161 +3
- Misses 545 549 +4
- Partials 310 312 +2
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. |
slang25
force-pushed
the
slang25/v9-aot
branch
2 times, most recently
from
August 9, 2026 11:44
2a004d4 to
c7dfaa3
Compare
Add a source-generated serialization path to SystemTextJsonMessageBodySerializer<T> alongside the reflection-based one. On net8.0+, serialization branches on JsonSerializer.IsReflectionEnabledByDefault: the reflection path is used when available, otherwise the source-generated JsonTypeInfo<T> from the supplied options is used (throwing the documented NotSupportedException if the type is absent from the context). Both paths serialize by the declared type T, so output is identical across reflection, trimming and AOT. - New JsonSerializerOptionsExtensions.GetTypeInfo<T>() (net8.0+). - DefaultJsonSerializerOptions only adds the (dynamic-code-requiring) JsonStringEnumConverter when dynamic code is supported. - The parameterless ctor is annotated [RequiresUnreferencedCode]/ [RequiresDynamicCode] because the default options carry no TypeInfoResolver. Behaviour under the JIT is unchanged; 294/294 unit tests pass. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Change the default IMessageBodySerializationFactory from Newtonsoft.Json to System.Text.Json across all three registration paths (the fluent default service resolver, the Microsoft.Extensions.DependencyInjection extensions and the StructureMap registry). This makes the default path source-generator- and Native-AOT-friendly. Newtonsoft.Json remains fully supported as an explicit opt-in. The change is a behavioural one (the default wire format) and is captured in MIGRATION-v9.md. Unit suite 294/294 (the one test that asserted the Newtonsoft default now asserts System.Text.Json). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Make the library's own JSON handling source-generator-friendly and annotate the Newtonsoft escape hatch ahead of enabling IsAotCompatible: - New internal source-generated JustSayingSerializationContext for the two internal JSON shapes (RedrivePolicy and the SNS account-id list); RedrivePolicy and SnsPolicyBuilder use it on net8.0+, falling back to reflection elsewhere. - NewtonsoftMessageBodySerializer<T> and NewtonsoftSerializationFactory are annotated [RequiresUnreferencedCode]/[RequiresDynamicCode] on their constructors, with [UnconditionalSuppressMessage] on the serialize/deserialize members (the caller opts into Newtonsoft's trimming/AOT requirements). Behaviour is unchanged under the JIT; 294/294 unit tests pass. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Turn on IsAotCompatible for all net8.0+ targets, which enables the trim/AOT/ single-file analyzers repo-wide. Thanks to the System.Text.Json default and the source-generated internal JSON, the only required fix was annotating the handler type parameter on AddJustSayingHandler<TMessage, THandler> with [DynamicallyAccessedMembers(PublicConstructors)] so DI can construct it under trimming. The core happy path is AOT-clean with no [RequiresUnreferencedCode] on AddJustSaying - reflection requirements are confined to the Newtonsoft escape hatch. Whole solution builds clean with analyzers on (0 IL/CS/RS); 294/294 unit tests. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Prove the full publish -> subscribe -> handle pipeline and source-generated System.Text.Json serialization survive Native AOT: - tests/JustSaying.AotTest: a net10.0 PublishAot exe that runs an in-process round trip against LocalSqsSnsMessaging's in-memory AWS bus, registering a source-generated SystemTextJsonSerializationFactory. Notably it needs no [UnconditionalSuppressMessage] around AddJustSaying - the core is AOT-clean. - A native-aot (linux) CI job that publishes the app to a native binary and runs it; a non-zero exit fails the build. Verified locally: native publish (osx-arm64) produces a clean binary - the only IL2104/IL3053 warnings come from the test-only LocalSqsSnsMessaging dependency (demoted to warnings) - and the binary runs green under Native AOT. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1.0.1 ships fully trim/AOT-annotated, so the test-only IL2104/IL3053 warnings are gone. Drop the now-unnecessary WarningsNotAsErrors demotion from the AOT test project - it is strict again, the native publish is completely warning-free, and the binary still runs green under Native AOT. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add a source-generated ApplicationJsonContext and register a SystemTextJsonSerializationFactory built from it (and plug the same context into ASP.NET's minimal-API JSON pipeline) so JustSaying serialization in the sample uses source generation rather than reflection - the pattern an app needs to be Native-AOT-publishable. PublishAot is intentionally not set on this sample: it depends on Aspire ServiceDefaults / OpenTelemetry / Scalar, whose native-AOT readiness is out of JustSaying's scope. The dedicated tests/JustSaying.AotTest already proves the library itself runs as a native-AOT binary. Sample builds clean. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Fixes the STScJ typo and replaces the comment-only opt-in example with real registration for both containers, spelling out the ordering each one needs: Microsoft DI registers the default with TryAddSingleton so yours must come first, StructureMap takes the last registration so yours must come last. Also drops the reference to a fluent WithMessageBodySerializer hook, which does not exist. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
slang25
force-pushed
the
slang25/v9-aot
branch
from
August 11, 2026 00:30
c7dfaa3 to
ddf6baa
Compare
4 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
v9 stacked PR — 2 of 3 — Native AOT
Makes JustSaying Native AOT-compatible. Stacked on #2182 (review/merge that first).
Highlights
IsAotCompatibleenabled repo-wide. The only fix required was[DynamicallyAccessedMembers]on the DI handler type parameter — there are no[RequiresUnreferencedCode]annotations onAddJustSaying; reflection is confined to the Newtonsoft escape hatch.tests/JustSaying.AotTest: aPublishAotapp running a full publish → subscribe → handle round trip in-memory — verified locally producing and running a clean native binary — plus anative-aot (linux)CI job that publishes and runs it.Messageconstraint from the DI handler-registration extensions (a foundation follow-up that landed in this range).294 unit tests + the native-AOT round trip green; solution builds clean with analyzers on.
Stack
slang25/v9-foundation)slang25/v9-cloudevents— CloudEvents + multi-type-per-queue🤖 Generated with Claude Code