Skip to content

NumericTextBox logs DeviceMode deserialization errors after trim/WASM AOT publish (1.0.2) #83

Description

@PureWeen

Summary

SfNumericTextBox<int> logs a DeviceMode deserialization/JS-interop initialization error when running the published output of a trimmed Blazor WebAssembly application. The error also occurs in the WebAssembly AOT-published output.

Restore and publication succeed. Initial value display, editing, and parent reset still work, so this is not a compilation failure or a claim that the entire control is unusable.

The four-file example below contains one Toolkit control, without forms, validation, an ErrorBoundary, or custom JavaScript. A ?native=1 branch renders a native input instead, using the same published files and service registration; that branch has no captured console error.

Environment

  • Package: Syncfusion.Blazor.Toolkit 1.0.2
  • Target: net10.0; .NET SDK 10.0.401
  • Microsoft.AspNetCore.Components.WebAssembly: 10.0.12
  • Windows; Microsoft Edge 152.0.4191.66; browser locale en-US
  • Both variants enable trimming. The second also sets RunAOTCompilation=true and performs WebAssembly AOT compilation.
  • The AOT variant requires the .NET 10 wasm-tools workload.

Self-contained reproduction

Using the SDK above, create an empty PublishRepro directory containing these four files. The wwwroot directory is a child of that directory.

PublishRepro.csproj

<Project Sdk="Microsoft.NET.Sdk.BlazorWebAssembly">
  <PropertyGroup>
    <TargetFramework>net10.0</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsings>enable</ImplicitUsings>
    <BlazorWebAssemblyLoadAllGlobalizationData>true</BlazorWebAssemblyLoadAllGlobalizationData>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="10.0.12" />
    <PackageReference Include="Syncfusion.Blazor.Toolkit" Version="1.0.2" />
  </ItemGroup>
</Project>

Program.cs

using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
using PublishRepro;
using Syncfusion.Blazor.Toolkit;

var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.Services.AddSyncfusionBlazorToolkit();
builder.RootComponents.Add<App>("#app");
await builder.Build().RunAsync();

App.razor

@using Microsoft.AspNetCore.Components
@using Microsoft.AspNetCore.Components.Web
@using Syncfusion.Blazor.Toolkit.Inputs
@inject NavigationManager Navigation

<h1>One NumericTextBox, without forms or validation</h1>
<label for="amount">Amount</label>
@if (native)
{
    <input id="amount" type="number" min="0" max="100" step="1" @bind="value" />
}
else
{
    <SfNumericTextBox TValue="int" ID="amount" @bind-Value="value" Min="0" Max="100" Step="1" />
}
<p>Bound value: <output id="model">@value</output></p>
<button id="reset" @onclick="() => value = 10">Reset</button>

@code {
    private int value = 10;
    private bool native;
    protected override void OnInitialized() =>
        native = new Uri(Navigation.Uri).Query.TrimStart('?').Split('&').Contains("native=1");
}

wwwroot\index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width,initial-scale=1" />
    <base href="/" />
    <title>NumericTextBox reproduction</title>
    <link rel="icon" href="data:," />
    <link rel="stylesheet" href="_content/Syncfusion.Blazor.Toolkit/styles/fluent.min.css" />
</head>
<body>
    <div id="app">Loading...</div>
    <script src="_framework/blazor.webassembly.js"></script>
</body>
</html>

Publish and serve the actual output

Run from PublishRepro. Keep the two output directories outside the project directory:

dotnet publish .\PublishRepro.csproj -c Release -o ..\output-trim -p:PublishTrimmed=true -p:RunAOTCompilation=false -p:EnableTrimAnalyzer=true -p:EnableAotAnalyzer=true -p:SuppressTrimAnalysisWarnings=false -p:TrimmerSingleWarn=false
dotnet publish .\PublishRepro.csproj -c Release -o ..\output-aot -p:PublishTrimmed=true -p:RunAOTCompilation=true -p:EnableTrimAnalyzer=true -p:EnableAotAnalyzer=true -p:SuppressTrimAnalysisWarnings=false -p:TrimmerSingleWarn=false

Serve the first output with a static HTTP server. The reproduction used Python's standard-library server:

python -m http.server 5000 --bind 127.0.0.1 --directory ..\output-trim\wwwroot
  1. Open http://127.0.0.1:5000/ with the browser console visible and wait for the control to initialize.
  2. Observe the error below. The initial bound value is still 10; typing 23 and leaving the input updates the model, and Reset returns both model and input to 10.
  3. Open http://127.0.0.1:5000/?native=1 in a fresh page/context. The native input has the same initial/edit/reset behavior but no captured console error.
  4. Stop the static server, serve ..\output-aot\wwwroot instead, and repeat in fresh browser contexts to avoid mixing cached artifacts.

Do not substitute dotnet run or the development build for these published-output checks.

Actual diagnostic

Selected lines from the browser console; wrapper and stack lines omitted:

fail: Syncfusion.Blazor.Toolkit.Inputs.SfNumericTextBox[2014]
      Unexpected error in OnAfterRenderAsync.
 ---> System.NotSupportedException: DeserializeNoConstructor, JsonConstructorAttribute, Syncfusion.Blazor.Toolkit.DeviceMode

The captured stack also includes UpdateIsDeviceModeAsync and OnAfterScriptRenderedAsync.

Published artifact Toolkit branch Native branch in the same artifact
Trimmed, AOT disabled Initialization error above; initial/edit/reset operations pass Initial/edit/reset operations pass; no captured console error
Trimmed, AOT enabled Initialization error above; initial/edit/reset operations pass Initial/edit/reset operations pass; no captured console error

No page-level unhandled exception or failed HTTP response was captured in these four browser runs; the reported failure is the component's logged initialization error.

Expected behavior and scope

The control should initialize without this deserialization/interop error in the supported published configuration. If either configuration is unsupported, please clarify the applicable limitation.

This report is specific to Toolkit 1.0.2, the sample and environment above, and WebAssembly trimming/AOT. It does not establish the underlying source-level cause, a failure in all component operations, or behavior in other versions.

Related context: #79. This is published-runtime evidence; the earlier package report's comparison-source analyzer results did not establish this runtime behavior.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions