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

如何用FluentValidation实现Address类Phone/Mobile至少一项必填验证?

解决Address类中Phone与Mobile至少填写一个的验证问题

问题描述

我有一个包含Phone和Mobile属性的Address类,需要验证这两个属性中至少有一个已填写。尝试了三种FluentValidation规则均存在问题:

  • 第一种实体级规则完全无效;
  • 后两种字段级规则仅在对应字段修改时才生效,导致另一个字段的错误状态无法实时更新。

原验证器代码

public class AddressValidator : BaseValidator<Address>
{
    public AddressValidator()
        : base()
    {
        // NOT WORKING
        RuleFor(x => x)
           .Must(x => !string.IsNullOrEmpty(x.Phone) || !string.IsNullOrEmpty(x.Mobile))
           .WithMessage("Phone or mobile mandatory");

        // WORKS ONLY ON MOBILE FIELD CHANGED
        RuleFor(m => m.Mobile).Must((a, Mobile) =>
                    (!string.IsNullOrEmpty(a.Phone) || !string.IsNullOrEmpty(Mobile)))
                    .WithMessage("Phone or mobile mandatory");

         // WORKS ONLY ON PHONE FIELD CHANGED
        RuleFor(m => m.Phone).Must((a, Phone) =>
                    (!string.IsNullOrEmpty(a.Mobile) || !string.IsNullOrEmpty(Phone)))
                    .WithMessage("Phone or mobile mandatory");
    }
}

原Blazor表单代码

<EditForm Context="billing" Model=@Address>
 <FluentValidationValidator DisableAssemblyScanning="@true" @ref="validatorAddress"></FluentValidationValidator>                   
                <div class="row">
                    <div class="col-sm-6">
                        <TextBox TValue="string"
                         @bind-Value=@Address.Phone />
                        <ValidationMessage For="@(() => Address.Phone )" />
                    </div>
                    <div class="col-sm-6">
                        <TextBox TValue="string"
                         @bind-Value=@Address.Mobile/>
                        <ValidationMessage For="@(() => Address.Mobile)" />
                    </div>
                </div>
   </Editform>

解决方案

1. 修正FluentValidation验证器

调整验证规则,确保两个字段的规则互相关联,同时配置级联模式保证所有规则执行:

public class AddressValidator : BaseValidator<Address>
{
    public AddressValidator()
    {
        // 设置级联模式为Continue,确保所有规则都能执行
        CascadeMode = CascadeMode.Continue;

        // 验证Phone:若Phone为空,Mobile必须非空
        RuleFor(x => x.Phone)
            .Must((model, phone) => !string.IsNullOrEmpty(phone) || !string.IsNullOrEmpty(model.Mobile))
            .WithMessage("Phone or mobile is mandatory");

        // 验证Mobile:若Mobile为空,Phone必须非空
        RuleFor(x => x.Mobile)
            .Must((model, mobile) => !string.IsNullOrEmpty(mobile) || !string.IsNullOrEmpty(model.Phone))
            .WithMessage("Phone or mobile is mandatory");

        // 可选:添加实体级规则,确保表单提交时整体验证通过
        RuleFor(x => x)
            .Must(x => !string.IsNullOrEmpty(x.Phone) || !string.IsNullOrEmpty(x.Mobile))
            .WithMessage("Phone or mobile is mandatory")
            .OverridePropertyName("Phone"); // 将实体级错误关联到Phone字段,方便前端显示
    }
}

2. 调整Blazor表单触发跨字段验证

由于Blazor默认仅验证当前修改的字段,需在字段变更时手动触发另一个字段的验证,确保错误状态实时更新:

表单代码修改

<EditForm Context="billing" Model=@Address>
 <FluentValidationValidator DisableAssemblyScanning="@true" @ref="validatorAddress"></FluentValidationValidator>                   
                <div class="row">
                    <div class="col-sm-6">
                        <TextBox TValue="string"
                         @bind-Value=@Address.Phone
                         ValueChanged="@(() => ValidateField(() => Address.Mobile))" />
                        <ValidationMessage For="@(() => Address.Phone )" />
                    </div>
                    <div class="col-sm-6">
                        <TextBox TValue="string"
                         @bind-Value=@Address.Mobile
                         ValueChanged="@(() => ValidateField(() => Address.Phone))" />
                        <ValidationMessage For="@(() => Address.Mobile)" />
                    </div>
                </div>
   </Editform>

添加验证触发方法

在Blazor组件代码中添加以下方法,用于手动触发指定字段的验证:

private FluentValidationValidator? validatorAddress;

private async Task ValidateField<T>(Expression<Func<T>> field)
{
    if (validatorAddress != null)
    {
        await validatorAddress.ValidateAsync(field);
    }
}

问题原因说明

  • 实体级规则:Blazor的FluentValidation集成默认不会在单个字段变更时触发实体级验证,仅在表单提交或手动调用整体验证时生效,因此无法实时显示错误。
  • 单一字段级规则:仅在对应字段修改时执行验证,导致另一个字段的错误状态无法同步更新,比如修改Phone后,Mobile的旧错误不会自动消失。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 20:15:46