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

.NET 6 MVC自定义RequiredIf条件验证属性不生效问题

问题根因

你的验证不生效是3个核心问题叠加导致的:

  1. POST方法逻辑错误:Create提交接口里ModelState.IsValid校验失败时直接return null,框架会返回204无内容响应,不会回到表单视图,也不会输出验证错误,自然看不到触发效果。而且外层套的try-catch完全无意义,模型验证流程不会抛异常,catch分支永远走不到。
  2. 自定义验证特性默认不校验空值:直接继承ValidationAttribute的自定义特性,默认不会对null、空字符串类型的输入执行IsValid逻辑——只有内置的RequiredAttribute默认会对空值做校验。另外你原来写的反射取属性名的逻辑完全冗余:传入的PropertyName本身就是当前属性的名称,反射取到的Name属性和它永远相等,等于做了无用功,一旦传入的属性名不存在还会直接抛空引用异常。
  3. .NET 6可空类型隐式验证冲突:.NET 6项目模板默认启用可空引用类型,你模型里的FirstName、LastName声明为非可空string,框架模型绑定阶段会自动给这些属性加内置的Required验证,优先于你的自定义验证执行,逻辑会被打乱。
修复步骤

1. 修正控制器提交逻辑

把Create的POST方法改成验证失败时返回原视图,传入模型才能正常展示错误:

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(Person personModel)
{
    if(ModelState.IsValid)
    {
        return RedirectToAction(nameof(Index));
    }
    // 验证失败返回表单视图,传入当前模型
    return View(personModel);
}

其他Edit、Delete动作的逻辑如果后续要加验证,也要遵循同样的规则,不要在验证失败时返回null。

2. 重写自定义验证特性

让特性支持空值校验,去掉冗余的反射逻辑,修复后的代码如下:

[AttributeUsage(AttributeTargets.Property)]
public class RequiredIfAttribute : ValidationAttribute, IClientModelValidator
{
    private readonly string _propertyName;
    private readonly bool _desiredConfigValue;

    public RequiredIfAttribute(string propertyName, bool desiredConfigValue)
    {
        _propertyName = propertyName;
        _desiredConfigValue = desiredConfigValue;
    }

    // 标记特性需要验证上下文,强制框架对null/空值也执行校验
    public override bool RequiresValidationContext => true;

    protected override ValidationResult? IsValid(object? value, ValidationContext validationContext)
    {
        // 直接读静态配置判断当前字段是否需要必填
        var fieldConfig = RequiredFieldsData.PropertiesPair();
        bool needValidate = fieldConfig.TryGetValue(_propertyName, out bool configValue) 
                            && configValue == _desiredConfigValue;

        // 不需要必填的场景直接放行
        if (!needValidate)
        {
            return ValidationResult.Success;
        }

        // 需要必填时校验值是否为空
        if (string.IsNullOrWhiteSpace(value?.ToString()))
        {
            return new ValidationResult(ErrorMessage);
        }

        return ValidationResult.Success;
    }

    public void AddValidation(ClientModelValidationContext context)
    {
        MergeAttribute(context.Attributes, "data-val", "true");
        var errorMessage = FormatErrorMessage(context.ModelMetadata.GetDisplayName());
        MergeAttribute(context.Attributes, "data-val-requiredif", errorMessage);
        // 把验证参数传给前端,供客户端验证使用
        MergeAttribute(context.Attributes, "data-val-requiredif-property", _propertyName);
        MergeAttribute(context.Attributes, "data-val-requiredif-value", _desiredConfigValue.ToString().ToLower());
    }

    private bool MergeAttribute(IDictionary<string, string> attributes, string key, string value)
    {
        if (attributes.ContainsKey(key))
        {
            return false;
        }
        attributes.Add(key, value);
        return true;
    }
}

3. 关闭隐式必填验证冲突

在Program.cs里注册MVC服务的代码中,关闭非可空引用类型自动加Required特性的默认行为,避免框架内置验证干扰自定义逻辑:

builder.Services.AddControllersWithViews(options =>
{
    options.SuppressImplicitRequiredAttributeForNonNullableReferenceTypes = true;
});

如果你不想全局关闭这个配置,也可以把Person模型里的两个字符串属性改成可空类型:

public class Person
{
    public int Id { get; set; }

    [RequiredIf("FirstName", true, ErrorMessage = "First Name is required")]
    public string? FirstName { get; set; }

    [RequiredIf("LastName", true, ErrorMessage ="Last name is required")]
    public string? LastName { get; set; }
}

(可选)补全客户端验证

你现在只加了客户端验证的标记属性,没有对应的JS逻辑,前端无刷新验证不会生效。如果需要客户端即时校验,可以在站点公共JS文件里加如下适配代码:

$.validator.addMethod("requiredif", function (value, element) {
    // 如果需要做前端动态配置判断可以在这里扩展逻辑,简单场景直接后端校验也可以满足需求
    return value.trim().length > 0;
});
$.validator.unobtrusive.adapters.addBool("requiredif");

改完之后重新测试就能符合预期:FirstName配置为true时空值提交会触发错误,LastName配置为false时空值可以正常提交。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.03 08:12:32