Blazor WASM自定义唯一约束ValidationAttribute实现方案咨询
可行解决方案如下
方案1:远程校验组合标记属性(推荐,逻辑统一无冲突)
该方案完全规避Shared项目访问Server的限制,同时保证前后端校验逻辑一致:
- 在Shared项目中仅定义标记用的
UniqueAttribute,不包含任何校验逻辑,仅存储唯一校验关联的实体元数据:
[AttributeUsage(AttributeTargets.Property)] public class UniqueAttribute : Attribute { /// <summary> /// 对应校验的实体类型 /// </summary> public Type EntityType { get; } public UniqueAttribute(Type entityType) { EntityType = entityType; } }
- 给Shared项目中的实体属性添加上述标记,示例:
public class ApplicationUser { public int Id { get; set; } [Unique(typeof(ApplicationUser))] public string UserAccount { get; set; } }
- Server端新增通用唯一校验接口,接收参数为:实体类型名、校验属性名、属性值、当前编辑实体ID(编辑场景用于排除自身),查询DBContext返回是否存在重复值即可。
- Client项目中实现客户端侧的自定义校验属性,继承
ValidationAttribute,内部调用你封装的HttpService请求上述校验接口,获取结果返回校验状态。Blazor的EditForm原生支持异步校验逻辑,结果返回后会自动标记对应Input控件的错误状态:
public class ClientUniqueValidationAttribute : ValidationAttribute { protected override async Task<ValidationResult> IsValidAsync(object value, ValidationContext validationContext) { var httpService = validationContext.GetRequiredService<IHttpService>(); var uniqueAttr = validationContext.ObjectType .GetProperty(validationContext.MemberName) .GetCustomAttribute<UniqueAttribute>(); // 调用后端校验接口 var isDuplicate = await httpService.PostAsync<bool>("/api/validation/check-unique", new { EntityName = uniqueAttr.EntityType.Name, PropertyName = validationContext.MemberName, InputValue = value?.ToString(), CurrentId = (validationContext.ObjectInstance as IEntityBase)?.Id }); return isDuplicate ? new ValidationResult($"{validationContext.DisplayName}已存在,请更换") : ValidationResult.Success; } }
注意:前端校验仅为提升用户体验的前置逻辑,你已实现的后端唯一约束必须保留,防止恶意请求绕过前端校验直接调用接口。
方案2:前端预缓存校验(仅适合小数据量场景)
如果需要校验的实体数据量极小(如少于100条的字典类数据),可以在页面初始化时一次性拉取所有已存在的属性值到前端缓存,自定义校验属性直接在前端匹配缓存判断是否重复。该方案不需要实时请求接口,但实时性差,数据量大时会浪费带宽,不推荐通用场景使用。
方案3:封装通用校验组件
可以针对需要唯一校验的输入场景封装单独的InputUniqueText组件,将远程校验逻辑内置在组件内部,复用性更高,不需要每个表单单独配置校验规则。
内容的提问来源于stack exchange,提问作者Josh Johner
相关产品推荐
相关产品推荐

