Skip to content

Fix trim/AOT safety for custom event argument deserialization in Blazor - #68113

Open
NanthiniMahalingam wants to merge 4 commits into
dotnet:mainfrom
NanthiniMahalingam:fix-45851
Open

Fix trim/AOT safety for custom event argument deserialization in Blazor#68113
NanthiniMahalingam wants to merge 4 commits into
dotnet:mainfrom
NanthiniMahalingam:fix-45851

Conversation

@NanthiniMahalingam

@NanthiniMahalingam NanthiniMahalingam commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Bug description

  • When a Blazor component uses a custom event (registered via [EventHandler]) whose event-args type is deserialized from JSON, the members of that type could be trimmed away in trimmed/AOT-published apps. The deserialization path in WebEventData relied on JsonSerializer.Deserialize(string, Type, options), which is annotated RequiresUnreferencedCode.
  • That warning was being hidden with an UnconditionalSuppressMessage rather than actually being made trim-safe, so custom event args could fail to deserialize at runtime after trimming.

Root cause

  • The custom event-args Type flows from [EventHandler(..., Type eventArgsType)] → Renderer.GetEventArgsType(...) → JSON deserialization, but the Type was not annotated with [DynamicallyAccessedMembers]. The trimmer therefore had no signal to preserve the JSON-required members.
  • WebEventData.ParseEventArgsJson used the reflection-based JsonSerializer.Deserialize overload (RequiresUnreferencedCode) and merely suppressed the IL2026 warning, masking the real trimming hole instead of closing it.

Description of code changes

  • Annotated the eventArgsType constructor parameters and the EventArgsType property on EventHandlerAttribute.cs with DynamicallyAccessedMembers(LinkerFlags.JsonSerialized), so the members needed for JSON (de)serialization are preserved through trimming.
  • Annotated the return value of EventArgsTypeCache.GetEventArgsType with [return: DynamicallyAccessedMembers(JsonSerialized)] and added a justified IL2073 suppression (the type originates from the annotated EventHandlerAttribute).
  • Annotated the return value of the public Renderer.GetEventArgsType(ulong) so the annotation propagates to callers.
  • In WebEventData.cs, switched to the trim-safe API: resolve JsonTypeInfo via jsonSerializerOptions.GetTypeInfo(eventArgsType) and deserialize with that, removing the now-unnecessary UnconditionalSuppressMessage suppression.

Fixes #45851

Output

Before changes

beforefix-45851.mp4

After changes

afterfix-45851.mp4

@dotnet-policy-service dotnet-policy-service Bot added the community-contribution Indicates that the PR has been added by a community member label Jul 30, 2026
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Thanks for your PR, @NanthiniMahalingam. Someone from the team will get assigned to your PR shortly and we'll get it reviewed.

@NanthiniMahalingam
NanthiniMahalingam marked this pull request as ready for review August 4, 2026 11:24
@NanthiniMahalingam
NanthiniMahalingam requested a review from a team as a code owner August 4, 2026 11:24
Copilot AI review requested due to automatic review settings August 4, 2026 11: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.

Pull request overview

Fixes a trimming/AOT reliability issue in Blazor’s custom browser-event argument deserialization by ensuring the event-args Type carries the correct linker annotations and by switching the deserialization path to the JsonTypeInfo-based API.

Changes:

  • Propagates DynamicallyAccessedMembers(JsonSerialized) through EventHandlerAttribute, Renderer.GetEventArgsType, and EventArgsTypeCache.GetEventArgsType so JSON-required members aren’t trimmed away.
  • Updates WebEventData.ParseEventArgsJson to deserialize via JsonSerializerOptions.GetTypeInfo(...) + JsonSerializer.Deserialize(..., JsonTypeInfo) and removes the previous IL2026 suppression.
  • Adds coverage: a focused unit test for the custom-event deserialization path and an E2E regression test validating behavior in trimmed WASM publishes.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
src/Components/Web/test/WebEventData/WebEventDataTest.cs Adds unit tests for custom event-args deserialization behavior (typed handler vs parameterless).
src/Components/Web/src/WebEventData/WebEventData.cs Removes the IL2026 suppression and switches to JsonTypeInfo-based deserialization for trim safety.
src/Components/test/E2ETest/Tests/WebAssemblyTrimmingTest.cs Adds a trimmed-WASM regression test for custom event args surviving trimming.
src/Components/Components/src/RenderTree/Renderer.cs Annotates GetEventArgsType return value to propagate linker requirements to callers.
src/Components/Components/src/RenderTree/EventArgsTypeCache.cs Annotates return value and adds an IL2073 suppression for the reflection-derived parameter type.
src/Components/Components/src/EventHandlerAttribute.cs Annotates eventArgsType parameters and EventArgsType property with DynamicallyAccessedMembers(JsonSerialized).

Comment thread src/Components/Components/src/RenderTree/EventArgsTypeCache.cs Outdated
Comment thread src/Components/Web/src/WebEventData/WebEventData.cs Outdated
@sheiksyedm
sheiksyedm requested a lite review from Copilot August 12, 2026 08:32
@sheiksyedm sheiksyedm added the area-blazor Includes: Blazor, Razor Components label Aug 12, 2026

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.

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated no new comments.

Suppressed comments (1)

src/Components/test/E2ETest/Tests/WebAssemblyTrimmingTest.cs:94

  • The test name/comments indicate this is specifically validating behavior in a trimmed/published app, but it currently runs unconditionally (unlike the other trimming tests in this class). This can give a false sense of trimming coverage when TestTrimmedApps is false, and it also makes the assertion less strict by using LastOrDefault() instead of asserting a single log entry.
    [Fact]
    public void CustomEventArgsAreDeserialized_WhenPublishedWithTrimming()
    {
        // Regression test for https://github.com/microsoft/fast-blazor/issues/280, where custom
        // event args types were trimmed away in assemblies marked IsTrimmable=true, causing
        // deserialization to fail at runtime. The members required to deserialize a custom event
        // args type are preserved through the [EventHandler] attribute's DynamicallyAccessedMembers
        // annotation. This test runs against the trimmed BasicTestApp so it validates that the
        // custom event args type (and the members needed to JSON-deserialize it) survive trimming.
        var appElement = Browser.MountTestComponent<EventCustomArgsComponent>();

        appElement.FindElement(By.Id("register-testevent-with-createventargs-that-supplies-args")).Click();
        appElement.FindElement(By.Id("trigger-testevent-directly")).Click();

        // If the custom event args type had been trimmed, deserialization would fail and MyProp
        // would never be populated. Observing the value confirms the members were preserved.
        Browser.Equal(
            "Received testevent with args '{ MyProp=Native event target ID=test-event-target-child }'",
            () => GetLogLines(appElement).LastOrDefault());
    }

@kotlarmilos
kotlarmilos requested a review from javiercn August 12, 2026 10:18
@kotlarmilos

Copy link
Copy Markdown
Member

Thanks, I consider it being risky for .NET 11. Can we push it for .NET 12?

@sheiksyedm sheiksyedm added this to the .NET 12 Planning milestone Aug 14, 2026
@Youssef1313 Youssef1313 removed this from the .NET 12 Planning milestone Sep 2, 2026
@kotlarmilos

Copy link
Copy Markdown
Member

NanthiniMahalingam Let's move it to the backlog and revisit it after .NET 11 GA.

@kotlarmilos kotlarmilos added this to the .NET 12 Planning milestone Sep 3, 2026
@Youssef1313

Copy link
Copy Markdown
Member

We should track milestone only in the linked issue, not in the PR.

@Youssef1313 Youssef1313 removed this from the .NET 12 Planning milestone Sep 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-blazor Includes: Blazor, Razor Components community-contribution Indicates that the PR has been added by a community member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

WebEventData.ParseEventArgsJson has invalid UnconditionalSuppressMessage for JsonSerializer.Deserialize

5 participants