Skip to content

Add Model + FieldName overload for InputBase and ValidationMessage to avoid expression parsing #61711

Open
@nmachek

Description

@nmachek

Is there an existing issue for this?

  • I have searched the existing issues

Is your feature request related to a problem? Please describe the problem.

Currently, Blazor’s InputBase and ValidationMessage components require a ValueExpression (e.g., @(() => Model.Property)) to create a FieldIdentifier.

While very convenient and expressive for developers, this design has measurable runtime costs:

  • Expression parsing is relatively slow, especially when done for many components at once (e.g., large or dynamic forms).
  • Memory allocations for closure objects, captured variables, and parsed trees add additional pressure.
  • On WebAssembly (WASM), where CPU/memory is limited, this cost is even more visible.

Even the internal FieldIdentifier.cs file acknowledges the cost concern:

// It would be great to cache this somehow, but it's unclear there's a reasonable way to do
// so, given that it embeds captured values such as "this". We could consider special-casing
// for "() => something.Member" and building a cache keyed by "something.GetType()" with values
// of type Func<object, object> so we can cheaply map from "something" to "something.Member".

This shows that the Blazor team itself recognized that expression parsing is non-trivial and expensive.

However, caching strategies are difficult because of captured closure values, instance-specific references (this), and type safety.

Describe the solution you'd like

Introduce optional parameters for "Model" and "FieldName" on InputBase and ValidationMessage components.

If developers opt-in, Blazor can completely skip parsing the ValueExpression and build a FieldIdentifier directly.

Example:

<InputText Model="Address" FieldName="Street" />
<ValidationMessage Model="Address" FieldName="Street" />

Behind the scenes, FieldIdentifier can be created like:

new FieldIdentifier(model, fieldName)

No parsing.
No closures.
No slow reflection.

I would have created my own components inheriting from InputBase but I had to provide a dummy ValueExpression so that SetParametersAsync doesn't throw an Exception. Even if I precompute the FieldIdentifier in OnInitialized, I cannot avoid the parsing of ValueExpression in SetParametersAsync.

Additional context

Why this makes sense

  • Backward compatible: Existing @(() => Model.Property) usage remains unchanged.
  • Opt-in optimization: Only those who want max performance need to use Model+FieldName.
  • Zero runtime cost: Initialization of FieldIdentifier happens once during OnInitialized().
  • Helps dynamic UI: Forms generated dynamically would benefit enormously.
  • WASM-friendly: Faster rendering on Blazor WebAssembly scenarios.
  • Simpler for large enterprise forms.

I estimate that bypassing expression parsing and directly accepting Model and FieldName in very large forms (100+ inputs) will improve considerably the user experience on page load while reducing CPU utilization.
Action Estimated cost per field
Parsing expression tree ~1.5 - 2 ms
Creating FieldIdentifier manually < 0.01 ms
Accessing property via instance < 0.001 ms

The risks are very low:

  • No breaking changes: all new functionality would be opt-in.
  • Advanced developers would choose the more verbose but faster path only if they need it.

Conclusion

Adding Model + FieldName overloads for Blazor input components is a small and safe improvement with big performance wins, especially for large or dynamic forms.

It aligns with the optimization hints already considered in the internal source code comments.

🙏 Thanks for considering this optimization!

Metadata

Metadata

Assignees

No one assigned

    Labels

    area-blazorIncludes: Blazor, Razor Components

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions