.NET 6 Blazor Server自定义数据验证注解异常排查求助
问题场景
在.NET 6 Blazor Server项目的EditForm中,有三个属性要求至少填写其中一个且不能为空白字符。为此自定义了RequiredIf数据注解,其IsValid方法代码如下:
protected override ValidationResult? IsValid(object? value, ValidationContext validationContext) { if (value != null) { return ValidationResult.Success; } int numberOfInvalidProperties = 0; object instance = validationContext.ObjectInstance; Type containerType = instance.GetType(); Type type = instance.GetType(); for (int i = 0; i < this.PropertyNames.Length; i++) { PropertyInfo? otherProperty = validationContext.ObjectType.GetProperty(this.PropertyNames[i]); if (otherProperty == null) { return new ValidationResult(string.Format(CultureInfo.CurrentCulture, "Could not find a property named '{0}'.", this.PropertyNames[i])); } object? propertyValue = otherProperty.GetValue(validationContext.ObjectInstance); if (propertyValue == this.DesiredValues[i]) { numberOfInvalidProperties++; } else if (otherProperty?.PropertyType == typeof(string)) { // treat empty strings as null if (this.DesiredValues[i] == null && string.IsNullOrWhiteSpace((string?)propertyValue)) { numberOfInvalidProperties++; } } } if (numberOfInvalidProperties == this.PropertyNames.Length) { return new ValidationResult(this.ErrorMessage, new[] { validationContext.MemberName }!); } else { return ValidationResult.Success; } }
模型的三个属性配置如下:
[RequiredIf(new string[] { "OrderNumber", "InternalOrderNumber" }, new object?[] { null, null }, ErrorMessage = "At least one of these is required")] public string CardStatementId { get; set; } [RequiredIf(new string[] { "OrderNumber", "CardStatementId" }, new object?[] { null, null }, ErrorMessage = "At least one of these is required")] public string InternalOrderNumber { get; set; } [RequiredIf(new string[] { "CardStatementId", "InternalOrderNumber" }, new object?[] { null, null }, ErrorMessage = "At least one of these is required")] public string OrderNumber { get; set; }
提交空表单时三个属性都显示错误,但存在两个问题:
- 填写任意一个属性的有效值后,仅该属性的错误提示消失,另外两个属性的错误提示仍存在(不阻止表单提交);
- 代码中已处理空白字符串的校验逻辑,且进入了
numberOfInvalidProperties == this.PropertyNames.Length分支,但未显示错误提示。
问题分析与解决
问题1:部分属性错误提示未自动消失
这是因为Blazor Server的EditForm默认仅触发当前被编辑属性的验证逻辑,其他属性的验证状态不会自动更新。当你填写其中一个属性后,只有该属性的RequiredIf验证被重新调用并返回成功,另外两个属性的错误状态仍停留在之前的校验结果。
解决方法:
- 方式一:给每个输入组件添加
ValueChanged事件,手动触发全模型验证。比如给InputText添加:
然后在组件中实现验证方法:<InputText @bind-Value="Model.CardStatementId" ValueChanged="@(() => ValidateModel())" />private async Task ValidateModel() { var validationContext = new ValidationContext(Model); ValidationResults.Clear(); Validator.TryValidateObject(Model, validationContext, ValidationResults, validateAllProperties: true); await EditContext.ValidateAsync(); StateHasChanged(); } - 方式二:改用对象级验证(实现
IValidatableObject接口)替代属性级自定义注解,这样每次验证都会扫描整个模型,所有属性的错误提示会同步更新。
问题2:空白字符串未触发错误提示
IsValid方法开头的判断逻辑存在漏洞:如果当前属性是空白字符串(如""或全空格),value是一个非null的字符串对象,会直接返回ValidationResult.Success,跳过后续的其他属性检查逻辑。
需要先将当前属性的空白字符串视为null处理,修改开头的判断:
// 先处理当前属性的空白字符串 if (value is string strValue) { if (string.IsNullOrWhiteSpace(strValue)) { value = null; } } if (value != null) { return ValidationResult.Success; }
这样空白字符串会被当作null处理,进而进入后续的其他属性检查逻辑,符合“不能为空/空白字符”的要求。
另外注意:模型中字符串属性默认初始化为空字符串""而非null,上述修改已经覆盖了这种场景,无需额外修改模型构造函数。
内容的提问来源于stack exchange,提问作者osswmi
相关产品推荐
相关产品推荐

