ASP.NET Core MVC自定义RequiredIf验证不显示错误且表单仍提交
ASP.NET Core MVC RequiredIf自定义验证客户端不生效问题修复
问题概述
基于ASP.NET Core MVC模型验证实现了RequiredIf自定义验证属性,需求是当指定属性等于特定值时,标记的属性为必填项。调试时服务端验证逻辑正常,但UI不显示错误提示,表单仍能提交。
问题根源
- 客户端验证参数缺失:自定义属性的
AddValidation方法仅添加了基础验证标记,未传递依赖属性名和目标值,客户端脚本无法获取验证所需的判断条件。 - 未注册jQuery验证规则:jQuery Validation默认不识别
requiredIf自定义验证类型,需要手动注册验证方法和unobtrusive适配器。 - 服务端逻辑错误:原
IsValid方法的判断逻辑不符合需求,错误地在依赖属性匹配时只要当前属性有值就返回成功,未处理依赖属性不匹配时的放行逻辑。
修复步骤
1. 修正自定义验证属性代码
修改RequiredIfAttribute的服务端验证逻辑,并完善客户端验证参数传递:
public class RequiredIfAttribute : ValidationAttribute, IClientModelValidator { private readonly string _propertyName; private readonly object _desiredValue; private readonly string _errorMessage; public RequiredIfAttribute(string propertyName, object desiredValue, string errorMessage) { _propertyName = propertyName ?? throw new ArgumentNullException(nameof(propertyName)); _desiredValue = desiredValue; _errorMessage = errorMessage ?? throw new ArgumentNullException(nameof(errorMessage)); } protected override ValidationResult IsValid(object value, ValidationContext context) { var instance = context.ObjectInstance; var propertyInfo = instance.GetType().GetProperty(_propertyName); if (propertyInfo == null) { return new ValidationResult($"依赖属性 {_propertyName} 不存在"); } var propertyValue = propertyInfo.GetValue(instance, null); // 核心逻辑:依赖属性匹配目标值时,当前属性必须非空;否则无需验证 if (Equals(propertyValue, _desiredValue)) { if (value == null || (value is string str && string.IsNullOrWhiteSpace(str))) { return new ValidationResult(GetErrorMessage()); } } return ValidationResult.Success; } public string GetErrorMessage() => _errorMessage; public void AddValidation(ClientModelValidationContext context) { if (context == null) throw new ArgumentNullException(nameof(context)); // 启用客户端验证 MergeAttribute(context.Attributes, "data-val", "true"); // 设置错误提示 MergeAttribute(context.Attributes, "data-val-requiredIf", GetErrorMessage()); // 传递依赖属性名给客户端 MergeAttribute(context.Attributes, "data-val-requiredIf-property", _propertyName); // 传递目标值给客户端 MergeAttribute(context.Attributes, "data-val-requiredIf-value", _desiredValue.ToString()); } private static bool MergeAttribute(IDictionary<string, string> attributes, string key, string value) { if (attributes.ContainsKey(key)) { return false; } attributes.Add(key, value); return true; } }
2. 添加客户端自定义验证脚本
在页面中加载完jQuery、jquery.validate和jquery.validate.unobtrusive之后,添加以下脚本,注册自定义验证规则和适配器:
<script> // 注册requiredIf验证方法 $.validator.addMethod("requiredIf", function (value, element, params) { const targetElement = $('[name="' + params.property + '"]'); if (!targetElement.length) return true; const currentTargetValue = targetElement.val(); // 依赖属性匹配目标值时,当前输入框必须非空 if (currentTargetValue === params.value) { return $.trim(value) !== ''; } // 不匹配时直接通过验证 return true; }); // 注册unobtrusive适配器,关联data属性和验证规则 $.validator.unobtrusive.adapters.add("requiredIf", ["property", "value"], function (options) { options.rules["requiredIf"] = { property: options.params.property, value: options.params.value }; options.messages["requiredIf"] = options.message; }); </script>
3. 验证依赖属性的客户端元素
确保依赖属性(如TransactionType)的客户端元素name属性与视图模型中的属性名一致,比如使用@Html.DropDownListFor(m => m.TransactionType, ...)会自动生成正确的name属性,保证客户端脚本能正确获取其值。
验证效果
修改完成后,当TransactionType等于指定值时,Creditor输入框为空会触发客户端验证,显示错误提示并阻止表单提交;服务端验证逻辑也会正确拦截不符合条件的请求。
内容的提问来源于stack exchange,提问作者Gino Mortillero
相关产品推荐
相关产品推荐

