Blazor Server中双属性自定义ValidationAttribute联动验证问题
Blazor Server跨字段验证同步更新错误状态的解决办法
问题根源
你的问题在于Blazor的DataAnnotationsValidator默认仅在被修改的属性上触发验证,而自定义LessThan10Attribute是字段级验证逻辑。当修改SampleIntB降低总和时,系统不会自动重新验证SampleIntA,导致旧的错误提示残留。
方案一:通过INotifyPropertyChanged同步触发关联字段验证
让ViewModel实现INotifyPropertyChanged接口,在修改一个属性时,主动触发另一个属性的PropertyChanged事件,迫使Blazor重新验证两个字段。
修改后的SampleClass代码:
using Sample.ValidationAttributes; using System.ComponentModel; using System.ComponentModel.DataAnnotations; namespace Sample.ViewModels { public class SampleClass : INotifyPropertyChanged { private int _sampleIntA; private int _sampleIntB; public event PropertyChangedEventHandler PropertyChanged; private void OnPropertyChanged(string propertyName) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } [Required] [DisplayName("Sample A")] [LessThan10(ErrorMessage = "Sample A + Sample B Must be less than 10")] public int SampleIntA { get => _sampleIntA; set { if (_sampleIntA != value) { _sampleIntA = value; OnPropertyChanged(nameof(SampleIntA)); // 修改A时触发B的属性变更,强制重新验证B OnPropertyChanged(nameof(SampleIntB)); } } } [Required] [DisplayName("Sample B")] [LessThan10(ErrorMessage = "Sample A + Sample B Must be less than 10")] public int SampleIntB { get => _sampleIntB; set { if (_sampleIntB != value) { _sampleIntB = value; OnPropertyChanged(nameof(SampleIntB)); // 修改B时触发A的属性变更,强制重新验证A OnPropertyChanged(nameof(SampleIntA)); } } } } }
此方案无需修改页面代码,仅通过ViewModel内部逻辑实现验证同步,保持了字段级验证的原有结构。
方案二:使用类级验证+手动触发整体验证
改用IValidatableObject接口实现类级别的跨字段验证,同时在页面中订阅字段变化事件,触发整个模型的验证,确保所有字段的错误状态同步更新。
第一步:修改ViewModel实现IValidatableObject
using System.ComponentModel.DataAnnotations; namespace Sample.ViewModels { public class SampleClass : IValidatableObject { [Required] [DisplayName("Sample A")] public int SampleIntA { get; set; } [Required] [DisplayName("Sample B")] public int SampleIntB { get; set; } public IEnumerable<ValidationResult> Validate(ValidationContext validationContext) { if (SampleIntA + SampleIntB > 10) { // 将错误关联到两个字段,确保两个<ValidationMessage>都显示提示 yield return new ValidationResult( "Sample A + Sample B Must be less than 10", new[] { nameof(SampleIntA), nameof(SampleIntB) }); } } } }
第二步:修改Razor页面订阅字段变化事件
@page "/SamplePage" @using Sample.Data; @using Sample.ViewModels; @inject SampleService sampleService <h3>SamplePage</h3> <EditForm Model="@sampleClass" EditContext="@_editContext"> <DataAnnotationsValidator /> <ValidationSummary /> <InputNumber id="SampleIntA" @bind-Value="sampleClass.SampleIntA" class="form-control" autocomplete="off" /> <ValidationMessage For="() => sampleClass.SampleIntA" class="help-block text-danger" /> <InputNumber id="SampleIntB" @bind-Value="sampleClass.SampleIntB" class="form-control" autocomplete="off" /> <ValidationMessage For="() => sampleClass.SampleIntB" class="help-block text-danger" /> </EditForm> @code { private SampleClass sampleClass; private EditContext _editContext; protected override async Task OnInitializedAsync() { sampleClass = sampleService.GetSampleClass(); _editContext = new EditContext(sampleClass); // 任何字段修改时,触发整个模型的验证 _editContext.FieldChanged += (sender, e) => _editContext.Validate(); } }
此方案更适合复杂的跨字段验证场景,错误信息可以统一管理,且无需维护字段级的验证属性。
内容的提问来源于stack exchange,提问作者Jay
相关产品推荐
相关产品推荐

