Description
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!