Consider the following code which is just a demo to show the problem I'm facing:
@page "/login"@using System.ComponentModel.DataAnnotations<EditForm Model="MyModel" FormName="LoginForm" OnValidSubmit="LoginUser"><DataAnnotationsValidator /><div><InputText type="text" @bind-Value="MyModel.Username" /><ValidationMessage For="() => MyModel.Username" /></div><div><InputText type="password" @bind-Value="MyModel.Password" /><ValidationMessage For="() => MyModel.Password" /></div><button type="submit"> Login</button></EditForm>@code { [SupplyParameterFromForm] public required LoginModel MyModel { get; set; } protected override void OnInitialized() => MyModel ??= new(); void LoginUser() { } public class LoginModel { [Required] public string? Username { get; set; } [Required] public string? Password { get; set; } }}
When I submit the form the form field names start with MyModel
:
Now I want to do the same with reflection so I can create a form builder component (for static SSR). Using the same demo code, consider this:
@page "/login2"@using System.ComponentModel.DataAnnotations@using System.Linq.Expressions@using System.Reflection<EditForm Model="MyModel" FormName="LoginForm" OnValidSubmit="LoginUser"><DataAnnotationsValidator /> @foreach (var prop in typeof(LoginModel).GetProperties()) { var inputType = prop.Name == "Username" ? "text" : "password";<div><InputText type="@inputType" Value="@(GetPropertyValue<string>(prop))" ValueChanged="val => SetPropertyValue(prop, val)" ValueExpression="GetPropertyExpression<string>(prop)" /><ValidationMessage For="GetPropertyExpression<string>(prop)" /></div> }<button type="submit"> Login</button></EditForm>@code { [SupplyParameterFromForm] public required LoginModel MyModel { get; set; } protected override void OnInitialized() => MyModel ??= new(); void LoginUser() { } public class LoginModel { [Required] public string? Username { get; set; } [Required] public string? Password { get; set; } } T? GetPropertyValue<T>(PropertyInfo prop) => (T?)prop.GetValue(MyModel, null); void SetPropertyValue(PropertyInfo prop, object? value) => prop.SetValue(MyModel, value); Expression<Func<T>> GetPropertyExpression<T>(PropertyInfo prop) { var model = Expression.Constant(MyModel); var selector = Expression.Property(model, prop.Name); return Expression.Lambda<Func<T>>(selector, []); }}
Now the form field names do not start with the MyModel
and the framework populates the ValidationMessage
with the default error of Required
.
How can I fix this naming issue?