Skip to content

feat(serialization): generate explicit closed serializer contexts for NativeAOT - #11382

Merged
ReubenBond merged 46 commits into
dotnet:mainfrom
ReubenBond:rb-nativeaot-serializer-contexts
Oct 6, 2026
Merged

ReubenBond merged 46 commits into
dotnet:mainfrom
ReubenBond:rb-nativeaot-serializer-contexts

Conversation

@ReubenBond

@ReubenBond ReubenBond commented Oct 1, 2026 •

Copy link
Copy Markdown
Member

Problem

Runtime generic construction cannot reliably provide native code for every closed serialization shape, particularly nested collections with value-type arguments. Applications need compile-time registrations which make codec and copier dependencies visible to the native compiler, alongside the serializer's existing metadata-based capabilities.

Solution

Add [GenerateSerializerContext<List<Dictionary<string, int>>>] on a partial SerializerContext, with AddSerializerContext service/builder registration. The generic attribute declares its root through its type argument using C# 11 or later, so the compiler enforces closed attribute arguments. Multiple attributes and partial declarations contribute to one generated graph. The generator follows serialized members and supported collection dependencies, constructs closed concrete implementations from the existing Orleans serializer pipeline, and retains aliases, type identifiers, reference tracking, and deep-copy semantics.

JIT and NativeAOT use one generated-first resolution pipeline: closed factories and canonical caches take priority, followed by registered implementation metadata and dependency injection. The common type resolver caches declared closed types and resolves additional names through preserved reflection metadata. Existing type-name filters and component validation apply throughout. Context registration composes with ordinary serializer registration.

Generated struct value serializers alias the same canonical field codec. Generic model factories include the closed array implementation services requested by their generated code, preserving optimized direct byte-array dispatch. Referenced codec and copier implementations supply their actual constructor and service-member metadata, including private fields and generated service properties, to determine the closed dependency graph. NativeAOT implementations use direct member access or static accessors; JIT applications also support generated dynamic accessors.

Closed service construction publishes an entire completed dependency graph atomically. Nested activation and generic-materialization failures fault the graph even when an outer constructor catches them; pending automatic cache entries roll back with the graph. Recursive dependencies retain provider-owned partially constructed instances. Optional copiers query and cache completed shallow-copy results during operations, preserving identity while bounding work across shared dependency graphs. Previously completed services remain reusable after failure.

During construction, dependencies resolve through provider-owned services and explicit TypeManifestOptions.AddSerializerService factories. External dependencies are supplied through closed constructor arguments or factories returning captured instances. External DI lookups fault a pending graph with registration guidance, keeping dependencies stable across separately built providers and mutable source collections. Outside construction, the stable facade delegates ordinary and keyed resolution to the actual built provider, preserving its registration snapshot, selection rules, and lifetimes.

Scope and rationale

NativeAOT publication targets .NET 10 and later. Support includes List<Dictionary<string, int>>, primitive leaves, generated class/struct/enum models, nullable values, zero-based arrays, and referenced generated models provided through implementation metadata. Closed codec graphs are bounded to 1,024 types. Separate metadata traversal follows generic arguments, array elements, implemented interfaces, and declaring types with limits of 1,024 closed types and 128 nested dependencies; visited types terminate finite cycles. Dictionary context registrations support the default equality comparer and report custom-comparer inputs explicitly. Ordinary activation selects the existing comparer-aware dictionary constructor. Managed array fallbacks retain multidimensional serialization and non-zero-bound copying through their preserved constructors.

NativeAOT reflection activation and generic materialization operate on preserved constructors and available closed native implementations. Contexts make the required closed implementations explicit to the compiler. Unsupported runtime instantiations and services produce meaningful errors. Narrow metadata/backend annotations describe these preservation boundaries; an internal polyfill retains the relevant annotations in the netstandard asset.

Generated API surfaces, compiled documentation, focused source/runtime contracts, and strict NativeAOT Contexts/Factories discovery manifests integrate with the centralized smoke matrix. The reusable static-factory infrastructure also supports the RPC-response work in #11379, with context discovery and documentation owned by this PR.

Microsoft Reviewers: Open in CodeFlow

Copilot AI balanced review requested due to automatic review settings October 1, 2026 20:21

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot review overview

🟡 Changes recommended

Transaction rollback and concurrent dependency-injection resolution have unresolved correctness issues.

Review effort: Balanced
Findings: 5 High severity · 1 Medium severity

Open (6)
What changed in this PR

Adds compile-time serializer contexts to Orleans so NativeAOT can compile closed codec and copier dependency graphs without runtime generic construction.

Changes:

  • Adds context generation, registration APIs, and explicit type resolution.
  • Introduces transactional service construction and a generated-only feature switch.
  • Adds documentation, runtime contracts, and NativeAOT smoke scenarios.
File Description
test/​Orleans.Serialization.UnitTests/​TrimFlowTests.cs Selects the intended registration overload.
test/​Orleans.NativeAotSmoke/​Orleans.NativeAotSmoke.csproj Configures native smoke scenarios.
test/​Orleans.NativeAotSmoke/​NativeAotEnvironment.cs Enforces native execution.
test/​Orleans.NativeAotSmoke/​Factories.smoke.json Declares strict factory smoke coverage.
test/​Orleans.NativeAotSmoke/​Factories.cs Runs factory contracts.
test/​Orleans.NativeAotSmoke/​Factories.Contracts.cs Checks publication and rollback behavior.
test/​Orleans.NativeAotSmoke/​Contexts.smoke.json Declares strict context smoke coverage.
test/​Orleans.NativeAotSmoke/​Contexts.cs Runs context contracts.
test/​Orleans.NativeAotSmoke/​Contexts.Contracts.cs Checks supported graphs and serialization semantics.
test/​Orleans.CodeGenerator.Tests/​StaticSerializerFactoryTests.cs Adds factory regression tests.
test/​Orleans.CodeGenerator.Tests/​SerializerInitializationTests.cs Checks registration and resolver initialization.
test/​Orleans.CodeGenerator.Tests/​SerializerContextTests.cs Tests generated contexts and diagnostics.
test/​Orleans.CodeGenerator.Tests/​Orleans.CodeGenerator.Tests.csproj Includes shared contracts and documentation models.
src/​Orleans.Serialization/​TypeSystem/​TypeConverter.cs Authorizes explicitly registered types.
src/​Orleans.Serialization/​TypeSystem/​SerializerContextTypeResolver.cs Resolves registered closed type names.
src/​Orleans.Serialization/​Serializers/​CodecProvider.cs Constructs and publishes closed service graphs.
src/​Orleans.Serialization/​SerializerRuntimeFeatures.cs Defines the generated-only feature switch.
src/​Orleans.Serialization/​SerializerContext.cs Adds the context base and recursive holders.
src/​Orleans.Serialization/​Hosting/​ServiceCollectionExtensions.cs Registers context-backed serialization services.
src/​Orleans.Serialization/​Hosting/​SerializerBuilderExtensions.cs Adds builder-level context registration.
src/​Orleans.Serialization/​GeneratedCodeHelpers/​OrleansGeneratedCodeHelper.cs Integrates closed factories and dependency checks.
src/​Orleans.Serialization/​Configuration/​TypeManifestOptions.cs Stores closed factories and context types.
src/​Orleans.Serialization/​Codecs/​DictionaryCodec.cs Adds default-comparer-only construction.
src/​Orleans.Serialization.Abstractions/​Orleans.Serialization.Abstractions.csproj Enables AOT compatibility analysis.
src/​Orleans.Serialization.Abstractions/​GenerateSerializerContextAttribute.cs Declares closed graph roots.
src/​Orleans.CodeGenerator/​SerializerFactoryGenerator.cs Generates concrete dependency factories.
src/​Orleans.CodeGenerator/​SerializerContextGenerator.cs Emits contexts and validates supported types.
src/​Orleans.CodeGenerator/​OrleansSourceGenerator.cs Registers incremental context generation.
src/​Orleans.CodeGenerator/​Diagnostics/​DiagnosticRuleId.cs Adds context diagnostic identifiers.
src/​Orleans.CodeGenerator/​AnalyzerReleases.Unshipped.md Records new diagnostics.
src/​api/​Orleans.Serialization/​Orleans.Serialization.cs Updates the generated serialization API surface.
src/​api/​Orleans.Serialization.Abstractions/​Orleans.Serialization.Abstractions.cs Updates the generated attribute API surface.
docs/​site/​src/​content/​docs/​toc.yml Links the context guide.
docs/​site/​src/​content/​docs/​host/​configuration-guide/​snippets/​serializer-contexts/​SerializerContexts.csproj Builds the documentation example.
docs/​site/​src/​content/​docs/​host/​configuration-guide/​snippets/​serializer-contexts/​SerializerContextExample.cs Demonstrates context registration and copying.
docs/​site/​src/​content/​docs/​host/​configuration-guide/​snippets/​serializer-contexts/​NativeContextPublish.props Demonstrates generated-only native publishing.
docs/​site/​src/​content/​docs/​host/​configuration-guide/​serializer-contexts.md Explains supported graphs and runtime behavior.
docs/​Docs.slnx Includes the compiled documentation project.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread src/Orleans.CodeGenerator/SerializerContextGenerator.cs
Comment thread src/Orleans.CodeGenerator/SerializerFactoryGenerator.cs Outdated
Comment thread src/Orleans.Serialization/Serializers/CodecProvider.cs Outdated
Comment thread src/Orleans.Serialization/Serializers/CodecProvider.cs Outdated
Comment thread src/Orleans.Serialization/Serializers/CodecProvider.cs Outdated
Comment thread src/Orleans.CodeGenerator/SerializerFactoryGenerator.cs Outdated
Copilot AI balanced review requested due to automatic review settings October 1, 2026 20:32

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot review overview

🟡 Changes recommended

Unresolved deadlock, publication, rollback, and generic-array dependency issues affect correctness.

Review effort: Balanced
Findings: 7 High severity · 1 Medium severity

Open (8)
Previously missed (2)

In code that hasn't changed since last review

Medium severity Payload byte arrays register incompatible generic array dependencies

src/​Orleans.CodeGenerator/​SerializerFactoryGenerator.cs:200

For a supported Payload<T> with an [Id(0)] T[] member, a context rooted at Payload<byte> registers only ByteArrayCodec/ByteArrayCopier for the closed member type. The canonical generic implementation instead requests ArrayCodec<byte>/ArrayCopier<byte>, so resolving the model throws CodecNotFoundException. Register the concrete dependencies required by the generic-definition implementation, including their element services, in addition to the specialized closed-type implementations. Preserve the specialized byte[] wire format and add a Payload<byte> round-trip/copy regression test.

Medium severity Caught automatic child failures do not roll back transactions

src/​Orleans.Serialization/​GeneratedCodeHelpers/​OrleansGeneratedCodeHelper.cs:112

Automatic constructor failures here never set the active transaction's _constructionFailure; only exceptions escaping a registered factory do. In ordinary mode, an outer closed factory can catch an automatically activated child's failure and return successfully. Its incomplete root and any pending automatic dependencies then commit instead of rolling back. Record the failure before rethrowing from the generic helper, the non-generic CodecProvider activation path, and DI construction. Add a regression test where an automatic child caches a dependency, throws, and the outer factory catches the exception.

Comment thread src/Orleans.Serialization/Serializers/CodecProvider.cs Outdated
Comment thread src/Orleans.Serialization/Serializers/CodecProvider.cs Outdated
Copilot AI balanced review requested due to automatic review settings October 1, 2026 22:20
@ReubenBond
ReubenBond force-pushed the rb-nativeaot-serializer-contexts branch from 8d00ea6 to a6e8b3a Compare October 1, 2026 22:20

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Comment thread src/Orleans.CodeGenerator/SerializerFactoryGenerator.cs Outdated
Copilot AI balanced review requested due to automatic review settings October 1, 2026 23:24

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot review overview

🟡 Changes recommended

Context metadata and dependency-construction failures remain unresolved.

Review effort: Balanced
Findings: 4 High severity · 2 Medium severity

Open (6)
Resolved since last review (3)
Previously missed (1)

In code that hasn't changed since last review

Medium severity Referenced models ignore producer field-ID settings

src/​Orleans.CodeGenerator/​SerializerFactoryGenerator.cs:180

Referenced models are described using the consumer's GenerateFieldIds setting. A referenced implementation assembly built with OrleansGenerateFieldIds=PublicProperties can contain valid serialized auto-properties without [Id] attributes. A default-configured consumer treats those members as unassigned and reports ORLEANS0115, instead of traversing the producer's serialized dependencies. Preserve and consume the producer's effective member-selection metadata, and add a cross-project test with different field-ID settings. Explicit member IDs or a per-model field-ID setting can serve as a workaround.

Comment thread src/Orleans.CodeGenerator/SerializerFactoryGenerator.cs
Comment thread src/Orleans.Serialization/Serializers/CodecProvider.cs Outdated
Comment thread src/Orleans.Serialization/Serializers/CodecProvider.cs
Copilot AI balanced review requested due to automatic review settings October 2, 2026 07:42

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Comment thread src/Orleans.CodeGenerator/SerializerFactoryGenerator.cs
Comment thread src/Orleans.CodeGenerator/SerializerFactoryGenerator.cs
@github-actions

github-actions Bot commented Oct 2, 2026 •

Copy link
Copy Markdown
Contributor

Code coverage

Metric Pull request
Lines 83.17% (117,668 / 141,473)
Branches 72.70% (34,848 / 47,934)

Report-only conclusion: current-main baseline stale.

The newest successful coverage run tested 6bf11ad, not current main 1cc211b.

Coverage combines every CI test matrix job, including providers, CodeGen, .NET 8/10, Linux, Windows, and macOS, using canonical physical source and branch identities.

The comparison remains report-only while normal line and branch variance is calibrated.

Coverage details

Copilot AI balanced review requested due to automatic review settings October 2, 2026 09:52
@ReubenBond
ReubenBond force-pushed the rb-nativeaot-serializer-contexts branch from cca5c29 to e96b778 Compare October 2, 2026 09:52

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot review overview

🟡 Changes recommended

Unresolved referenced-accessor validation, recursive copier construction, and keyed service lookup failures block approval.

Review effort: Balanced
Findings: 4 High severity · 1 Medium severity

Open (5)
Resolved since last review (2)

Comment thread src/Orleans.CodeGenerator/SerializerFactoryGenerator.cs Outdated
Comment thread src/Orleans.CodeGenerator/SerializerFactoryGenerator.cs Outdated
Comment thread src/Orleans.Serialization/Serializers/CodecProvider.cs Outdated
Copilot AI balanced review requested due to automatic review settings October 2, 2026 14:41

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot review overview

🔵 Needs a closer look

Cross-cutting NativeAOT generation and concurrent service publication require final human review of execution and smoke-matrix evidence.

Review effort: Balanced
Findings: None

Resolved since last review (5)

Copilot AI balanced review requested due to automatic review settings October 2, 2026 17:15
@ReubenBond
ReubenBond force-pushed the rb-nativeaot-serializer-contexts branch from 8a584e0 to f314119 Compare October 2, 2026 17:15

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot review overview

🔵 Needs a closer look

Generator correctness issues remain, and cross-assembly generation and concurrent dependency publication need final human validation.

Review effort: Balanced
Findings: 2 High severity

Open (2)

Comment thread src/Orleans.CodeGenerator/SerializerFactoryGenerator.cs
Comment thread src/Orleans.CodeGenerator/SerializerFactoryGenerator.cs
Copilot AI balanced review requested due to automatic review settings October 2, 2026 17:25
Copilot AI balanced review requested due to automatic review settings October 5, 2026 23:19
@ReubenBond
ReubenBond force-pushed the rb-nativeaot-serializer-contexts branch from ac86a50 to 694be6b Compare October 5, 2026 23:19

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot review overview

🔵 Needs a closer look

Recursive construction and NativeAOT preservation require final human validation, alongside resolution of the retained correctness issue.

Review effort: Balanced
Findings: 1 Medium severity

Open (1)

Comment thread src/Orleans.CodeGenerator/SerializerFactoryGenerator.cs
Copilot AI balanced review requested due to automatic review settings October 5, 2026 23:59

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot review overview

🔵 Needs a closer look

NativeAOT preservation and recursive dependency publication require final human review and current CI confirmation.

Review effort: Balanced
Findings: None

Resolved since last review (1)

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot review overview

🔵 Needs a closer look

Recursive construction has an unresolved ownership regression, and the cross-cutting NativeAOT integration requires final human validation.

Review effort: Balanced
Findings: 1 High severity

Open (1)

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot review overview

🔵 Needs a closer look

Cross-cutting NativeAOT and recursive construction changes require final human review of managed, trimmed, and native integration evidence.

Review effort: Balanced
Findings: None

Resolved since last review (1)

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.

2 participants