Skip to content

[Blazor] Generate JS-invokable dispatch metadata - #68296

Draft
javiercn wants to merge 11 commits into
javiercn-aot-stack-1-stjfrom
javiercn-aot-stack-2-jsinterop
Draft

[Blazor] Generate JS-invokable dispatch metadata#68296
javiercn wants to merge 11 commits into
javiercn-aot-stack-1-stjfrom
javiercn-aot-stack-2-jsinterop

Conversation

@javiercn

@javiercn javiercn commented Aug 8, 2026

Copy link
Copy Markdown
Member

Stack

Layer 2 of 6. Depends on #68295 and targets javiercn-aot-stack-1-stj.

Summary

  • retain outbound JS call result types without runtime generic reconstruction
  • isolate reflection-based JS dispatch behind an internal resolver and independent compatibility switch
  • resolve generated JS-invokable descriptors before reflection
  • generate application JS-invokable metadata and consume registered contexts in RemoteJSRuntime
  • describe framework-owned Web callbacks and their callback-specific JSON contracts
  • verify the owning Web build emits and consumes BrowserFile and BrowserFile[] callback contracts while the shared WebAssembly build excludes inaccessible internal types
  • remove obsolete reflection helpers and broad warning suppressions

Review focus

Please review only the JSInterop runtime, generated dispatch metadata, and framework-owned JS callback provider in this layer. Component/bindable metadata, component runtime/discovery, framework component providers, and strict Native AOT proof are intentionally deferred to later stack layers.

Validation

  • Microsoft.JSInterop.Tests: 211 passed
  • JS metadata generator/provider tests: 10 passed
  • RemoteJSRuntimeMetadataTest: 5 passed
  • WebRendererJsonResolverTest: 4 passed
  • WasmLinkerTest build passed with 0 warnings
  • LinkabilityChecker passed with 0 warnings

javiercn and others added 11 commits August 9, 2026 13:20
Keep each outbound call's generic result type alive until completion so result deserialization no longer reconstructs it from runtime Type values.

Behavior: preserved
State: builds; parity coverage follows in the next commit
Review hint: the pending-call abstraction replaces TaskCompletionSource reflection without changing completion, cancellation, or failure flow.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Exercise typed completion for nullable outbound JS results in addition to the existing object, array, failure, and cancellation coverage.

Behavior: preserved
State: complete for typed pending-call completion

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Move method scanning, argument parsing, invocation, async adaptation, and caches behind an internal reflection resolver so DotNetDispatcher only coordinates wire dispatch.

Behavior: preserved
State: builds; generated resolution follows in the next commit
Review hint: the resolver contains the legacy reflection implementation and its suppressions; DotNetDispatcher now handles only protocol flow.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Expose executable JS-invokable descriptors and compose generated lookup ahead of an independently switchable reflection compatibility resolver.

Behavior: changed: runtimes can supply generated JS-invokable descriptors that take precedence over reflection
State: builds; dispatch matrix coverage follows in the next commit
Review hint: SourceGeneratedJSInvokableMethodResolver defines precedence and inheritance; the factory keeps reflection enabled by default behind its own linker-recognized switch.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Cover manual generated descriptors, generated-first precedence, inheritance and alias rules, misses, reflection parity, async completion, and object-reference disposal.

Behavior: preserved
State: complete for runtime descriptor resolution

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Add the JS-only metadata generator foundation, extend the experimental application context with JSInvokableMethods, and let RemoteJSRuntime flatten registered contexts into generated-first dispatch.

Behavior: changed: registered application metadata contexts now contribute generated JS-invokable methods
State: builds; generator and runtime integration tests follow in the next commit
Review hint: this layer emits only JsonTypeInfoResolver and JSInvokableMethods; component and bindable collection/emission are intentionally absent.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Exercise generated JS descriptors across method shapes, aliases, inheritance, and serialization, and verify registered contexts reach RemoteJSRuntime in registration order.

Behavior: preserved
State: complete for application-generated JS metadata
Review hint: the generator test project contains only the JS slice; component and bindable generator suites remain deferred.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Discover the Web assembly's built-in JS callback provider, spread its descriptors through generated contexts via UnsafeAccessor, and add callback-specific BrowserFile contracts only to the owning Web build.

Behavior: changed: generated application contexts now include framework-owned Web callbacks
State: builds; provider coverage follows in the next commit
Review hint: the generator only knows the provider assembly and factory shape; callback signatures and JSON contracts remain owned by Components.Web.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Verify generated contexts reach the Components.Web callback provider through the emitted UnsafeAccessor and include the complete built-in callback descriptor set.

Behavior: preserved
State: complete for framework callback metadata

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Delete the task-result generic reconstruction helper and broad linker warning XML now that pending calls retain result types and reflection suppressions sit beside the exact legacy operations.

Behavior: preserved
State: complete
Review hint: both deleted artifacts have no remaining callers or live suppression targets.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Prove the owning Components.Web serializer context emits BrowserFile and BrowserFile[] metadata and that the built-in NotifyChange descriptor consumes the array contract.

Behavior: preserved
State: complete
Review hint: this test guards the Web-only side of the existing COMPONENTS_WEBASSEMBLY conditional.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@javiercn
javiercn force-pushed the javiercn-aot-stack-2-jsinterop branch from a16a203 to e53c2c0 Compare August 9, 2026 11:28
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.

1 participant