fix(core): construct grain references without dynamic code - #11371
Conversation
There was a problem hiding this comment.
Copilot review overview
🟢 Approval recommended
The implementation preserves JIT behavior while adding focused NativeAOT handling, diagnostics, and comprehensive coverage.
Review effort: Balanced
Findings: None
What changed in this PR
Enables grain-reference construction under NativeAOT without changing the optimized JIT path.
Changes:
- Uses cached
ConstructorInvokerinstances when dynamic code is unavailable. - Adds JIT and NativeAOT coverage for proxy construction and failure behavior.
- Adds CI validation and implementation documentation.
| File | Description |
|---|---|
.github/workflows/analyzer-audit.yml |
Adds cross-platform NativeAOT smoke jobs. |
docs/site/src/content/docs/implementation/serialization.md |
Documents proxy construction paths. |
src/Orleans.Core/GrainReferences/GrainReferenceActivator.cs |
Adds the NativeAOT-compatible constructor path. |
src/Orleans.Core/Orleans.Core.csproj |
Exposes internals to the smoke executable. |
test/Orleans.Core.Tests/GrainReferences/GrainReferenceActivatorTests.cs |
Tests construction behavior and failures. |
test/Orleans.Core.Tests/Orleans.Core.Tests.csproj |
Links the shared fixture into unit tests. |
test/Orleans.GrainReferences.NativeAotSmoke/Orleans.GrainReferences.NativeAotSmoke.csproj |
Defines the NativeAOT executable. |
test/Orleans.GrainReferences.NativeAotSmoke/Program.cs |
Exercises construction under NativeAOT. |
test/Orleans.GrainReferences.NativeAotSmoke/README.md |
Explains smoke-test scope and usage. |
test/Orleans.GrainReferences.NativeAotSmoke/ReferenceConstructionFixture.cs |
Provides shared production-provider fixtures. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Code coverage
Report-only conclusion: regressed. The current-main baseline is commit 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 |
26c2a6c to
73e65b6
Compare

Production
GrainReferenceActivatorProviderunconditionally emits aDynamicMethod, so NativeAOT reference construction throws even when the generated proxy constructor has been preserved.Use a cached
ConstructorInvokerwhen dynamic code is unavailable, and retain the existing emitted constructor delegate on JIT runtimes. GeneratedAddInterfaceProxyregistrations provide the static constructor/interface roots; narrowly scoped annotations document the collection-to-activation boundary. Constructor failures continue to propagate directly, and explicitly preserved non-public proxy constructors remain supported. These constructors are selected by runtime proxy metadata, so the native branch uses cached reflection; future generated context factories can bind constructors statically.Add focused production-provider cases in the existing
Orleans.Core.Testsproject and aGrainReferencesscenario in the shared reusableOrleans.NativeAotSmokeharness. The scenario covers generated inherited interfaces, grain keys, interface version, shared dependency identity, invocation options, and constructor failures.The shared harness and centralized discovery runner from #11367 are now merged into main.
GrainReferences.smoke.jsonregisters this feature with the existing Windows/Linux NativeAOT matrix. Itslegacy-visiblepolicy retains broader library AOT diagnostics and rejects warnings or errors from the production constructor path and proxy interface discovery. This feature contributes scenario source and metadata with no workflow or runner changes. The merged runner discovers both grain-reference platforms and successfully publishes, gates diagnostics, and executes this branch's win-x64 native scenario.The verified capability is runtime-selected, non-generic production grain-reference construction. The actual production path reproduces the original
DynamicMethodfailure before the fix and succeeds natively afterward. The scenario supplies realTypeConverterandCodecProviderdependencies with empty payload manifests to isolate construction from serializer manifest startup, tracked in #11368. Generic proxy closure, payload serialization, and full client/silo startup retain their separate NativeAOT requirements.Microsoft Reviewers: Open in CodeFlow