You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将ModelState校验错误传入MudBlazor ValidationSummary显示

实现方法

核心逻辑是把后端返回的校验错误写入Blazor表单的ValidationMessageStore,MudBlazor的ValidationSummary和输入框控件会自动读取这个存储里的错误信息渲染,不需要额外维护单独的错误字符串数组。

具体修改步骤

  • 替换直接绑定Model的EditForm写法,持有EditContext实例,配套初始化验证消息存储
  • 调整提交逻辑:请求发送前清空历史错误,仅在请求失败时读取后端返回的错误字典
  • 遍历错误字典,将字段和对应错误写入验证存储,通知UI刷新验证状态

修改后的完整代码

@page "/marketingeventcreate"

@inject HttpClient Http
@inject NavigationManager NavManager

@using System.Text.RegularExpressions
@using System.ComponentModel.DataAnnotations
@using OnlinePlatform.Support.Domain.Entities
@using OnlinePlatform.Support.Domain.Dtos

<EditForm EditContext="@editContext" OnValidSubmit="OnValidSubmit">
<DataAnnotationsValidator/>
<MudGrid>
    <MudItem xs="12" sm="7">
        <MudCard>
            <MudCardContent>                
                <MudTextField Label="Event Name" HelperText=""
                              @bind-Value="model.Name" For="@(() => model.Name)"/>
                <MudTextField Label="Remark" Class="mt-3"
                              @bind-Value="model.Remark" For="@(() => model.Remark)"/>
                <MudTextField Label="Event Date" HelperText="" Class="mt-3" InputType="InputType.Date" 
                              Mask="@(new DateMask("dd.MM.yyyy"))" DateFormat="dd.MM.yyyy" 
                              @bind-Value="model.EventDate" For="@(() => model.EventDate)" />
                <MudTextField Label="Venue" HelperText="" Class="mt-3" 
                              @bind-Value="model.Venue" For="@(() => model.Venue)" />
                <MudTextField Label="State" HelperText="" Class="mt-3" 
                              @bind-Value="model.State" For="@(() => model.State)" />
                <MudTextField Label="Start Time" HelperText="i.e. 2000" Class="mt-3"
                              @bind-Value="model.StartTime" For="@(() => model.StartTime)" />
                <MudTextField Label="End Time" HelperText="i.e. 2100" Class="mt-3"
                              @bind-Value="model.EndTime" For="@(() => model.EndTime)"  />
            </MudCardContent>
            <MudCardActions>
                <MudButton ButtonType="ButtonType.Submit" Variant="Variant.Filled" Color="Color.Primary" Class="ml-auto">Submit</MudButton>
            </MudCardActions>
        </MudCard>
    </MudItem>
    <MudItem xs="12" sm="5">
        <MudPaper Class="pa-4 mud-height-full">
            <MudText Typo="Typo.subtitle2">Validation Summary</MudText>
            @if (success)
            {
                <MudText Color="Color.Success">Success</MudText>
            }
            else
            {
                <MudText Color="@Color.Error">
                    <ValidationSummary />
                </MudText>
            }
        </MudPaper>
    </MudItem>    
</MudGrid>
</EditForm>

@code {
    MarketingEvent model = new MarketingEvent();
    EditContext editContext;
    ValidationMessageStore validationMessageStore;
    bool success;

    protected override void OnInitialized()
    {
        editContext = new EditContext(model);
        validationMessageStore = new ValidationMessageStore(editContext);
    }

    private async Task OnValidSubmit(EditContext context)
    {
        success = false;
        // 清空上一次提交的历史错误
        validationMessageStore.Clear();
        
        var mydate = new DateTime(model.EventDate.Year, model.EventDate.Month, model.EventDate.Day);
        var request = new CreateMarketingEventRequest(model.Name, model.Remark, mydate, model.Venue, 
            model.State, model.StartTime?.ToString(), model.EndTime?.ToString());

        try
        {
            var response = await Http.PostAsJsonAsync("api/marketingevent", request);

            if (response.IsSuccessStatusCode)
            {
                if (response.StatusCode == System.Net.HttpStatusCode.Created)
                {
                    success = true;
                    NavManager.NavigateTo("/");
                    return;
                }
            }
            else
            {
                // 仅校验失败时读取错误字典,避免成功响应反序列化报错
                var serverErrors = await response.Content
                   .ReadFromJsonAsync<Dictionary<string, List<string>>>();

                if (serverErrors != null)
                {
                    foreach (var errorItem in serverErrors)
                    {
                        // 如果后端返回的是小驼峰字段名,用下面这行转成和C#属性匹配的大驼峰
                        string fieldName = char.ToUpperInvariant(errorItem.Key[0]) + errorItem.Key.Substring(1);
                        // 如果后端字段名和前端模型属性名大小写完全一致,直接用 errorItem.Key 即可
                        // string fieldName = errorItem.Key;
                        
                        FieldIdentifier field = editContext.Field(fieldName);
                        validationMessageStore.Add(field, errorItem.Value);
                    }
                    // 通知表单刷新验证状态
                    editContext.NotifyValidationStateChanged();
                }
            }
        }
        catch (Exception ex)
        {
            // 网络异常等非业务错误添加全局提示
            validationMessageStore.Add(editContext.Field(string.Empty), new[] { $"提交失败:{ex.Message}" });
            editContext.NotifyValidationStateChanged();
        }            
    }    
}

注意事项

  • 该方案不仅能让ValidationSummary显示所有后端错误,对应字段的MudTextField也会自动标红、在输入框下方显示专属错误提示,不需要额外绑定错误参数
  • 原有前端DataAnnotations校验逻辑完全不受影响,前后端校验错误会合并展示
  • 不对应具体字段的全局错误,给editContext.Field传空字符串即可,会显示在汇总区域顶部

内容的提问来源于stack exchange,提问作者Steve

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 10:51:21