Blazor Server中Fluent Validation如何校验输入值是否在外部列表中
解决方案
a) 将浏览器存储的列表传入验证器校验
首先修改SaveViewValidator,让它通过构造函数接收已存在的名称列表,新增重复校验规则:
namespace ITT_OneTeam.ViewModels { public class SaveView { public string? ViewName { get; set; } } public class SaveViewValidator : AbstractValidator<SaveView> { private readonly IEnumerable<string> _existingNames; // 构造函数注入已存在的视图名称列表 public SaveViewValidator(IEnumerable<string> existingNames) { _existingNames = existingNames; RuleFor(x => x.ViewName) .NotEmpty().WithMessage("Please enter the Name to be used.") // 校验输入名称是否不在已有列表中(忽略大小写) .Must(name => string.IsNullOrEmpty(name) || !_existingNames.Contains(name, StringComparer.OrdinalIgnoreCase)) .WithMessage("This view name already exists."); } } }
然后在Blazor组件中,通过JS互操作从浏览器localStorage获取列表,实例化验证器并关联到EditContext:
@inject IJSRuntime JSRuntime @using FluentValidation @using ITT_OneTeam.ViewModels @using System.Text.Json <EditForm EditContext="@editContext" OnValidSubmit="@HandleSubmit"> <ValidationSummary /> <div class="mb-3"> <label class="form-label">View Name</label> <InputText @bind-Value="model.ViewName" class="form-control" /> <ValidationMessage For="@(() => model.ViewName)" class="text-danger" /> </div> <button type="submit" class="btn btn-primary">Save</button> </EditForm> @code { private SaveView model = new(); private EditContext? editContext; private ValidationMessageStore? messageStore; protected override async Task OnInitializedAsync() { editContext = new EditContext(model); messageStore = new ValidationMessageStore(editContext); // 从localStorage读取已保存的视图名称列表 var storedNamesJson = await JSRuntime.InvokeAsync<string>("localStorage.getItem", "existingViewNames"); var existingNames = string.IsNullOrEmpty(storedNamesJson) ? new List<string>() : JsonSerializer.Deserialize<List<string>>(storedNamesJson)!; // 实例化验证器并绑定到EditContext var validator = new SaveViewValidator(existingNames); editContext.AddFluentValidation(validator); } }
b) 提交时动态添加错误并阻止提交
在提交方法中,使用ValidationMessageStore手动添加错误,触发验证状态变更来阻止提交:
private async Task HandleSubmit() { if (editContext == null) return; // 先执行已有验证规则 editContext.Validate(); // 动态获取最新的浏览器存储列表(防止提交前有其他操作修改了列表) var latestStoredJson = await JSRuntime.InvokeAsync<string>("localStorage.getItem", "existingViewNames"); var latestNames = string.IsNullOrEmpty(latestStoredJson) ? new List<string>() : JsonSerializer.Deserialize<List<string>>(latestStoredJson)!; // 检查当前输入是否已存在 if (!string.IsNullOrEmpty(model.ViewName) && latestNames.Contains(model.ViewName, StringComparer.OrdinalIgnoreCase)) { // 清空之前的自定义错误,添加新错误 messageStore?.Clear(); messageStore?.Add(editContext.Field(nameof(SaveView.ViewName)), "This view name is already taken."); // 通知验证状态变更,让UI显示错误 editContext.NotifyValidationStateChanged(); return; // 直接返回,阻止提交逻辑执行 } // 验证通过,执行提交逻辑 if (editContext.IsValid) { // 将新名称添加到列表并保存回localStorage latestNames.Add(model.ViewName!); await JSRuntime.InvokeVoidAsync("localStorage.setItem", "existingViewNames", JsonSerializer.Serialize(latestNames)); // 重置表单 model = new SaveView(); editContext = new EditContext(model); messageStore = new ValidationMessageStore(editContext); var validator = new SaveViewValidator(latestNames); editContext.AddFluentValidation(validator); } }
额外注意事项
- 确保已安装
FluentValidation.BlazorNuGet包,并且在Program.cs中添加服务注册:builder.Services.AddFluentValidationAutoValidation(); builder.Services.AddFluentValidationClientsideAdapters(); - 如果需要大小写敏感校验,去掉
StringComparer.OrdinalIgnoreCase即可。
内容的提问来源于stack exchange,提问作者Guillermo Perez
相关产品推荐
相关产品推荐

