.NET Core嵌套模型自定义验证AddValidation方法未触发如何解决
问题根源
你将[Select2Required]标注在UserViewModel的Branch复杂类型属性上,但分部视图中实际渲染的输入框绑定的是子属性Branch.Id。ASP.NET Core 的客户端验证属性生成是与当前绑定的字段路径严格对应的,路径不匹配的情况下,AddValidation方法不会将验证属性注入到Id对应的输入框上,因此客户端验证不生效。
方案1:手动传递错误信息(轻量灵活,适合快速实现)
这种方案不需要修改现有验证逻辑,只需要调整视图层代码即可实现多场景复用:
- 父视图传递错误信息
在渲染Select2分部视图时,将对应场景的错误信息通过ViewData传递到分部视图:
// 分支选择场景 @await Html.PartialAsync("_Select2Branch", Model.Branch, new ViewDataDictionary(ViewData) { {"Select2RequiredMsg", "Branch is required."} }) // 产品选择场景 @await Html.PartialAsync("_Select2Product", Model.Product, new ViewDataDictionary(ViewData) { {"Select2RequiredMsg", "Product is required."} })
- 分部视图注入客户端验证属性
修改分部视图代码,判断如果收到了必填错误信息,就自动为下拉框添加对应的客户端验证属性:
@model DataLibrary.ViewModels.BriefViewModels.BaseBriefViewModel @{ var elementId = ViewData["ElementId"] != null && !string.IsNullOrEmpty(ViewData["ElementId"].ToString()) ? ViewData["ElementId"].ToString() : "branch-id"; var requiredMsg = ViewData["Select2RequiredMsg"] as string; var htmlAttrs = new Dictionary<string, object> { {"id", elementId}, {"class", "form-control disable-field"} }; // 注入客户端验证属性 if (!string.IsNullOrEmpty(requiredMsg)) { htmlAttrs.Add("data-val", "true"); htmlAttrs.Add("data-val-select2-required", requiredMsg); } } <div class="form-group"> <label>Branch: <span class="text-danger"></span></label> <div class="row"> <div class="@select2Class"> @Html.DropDownListFor(model => model.Id, new List<SelectListItem>() { new SelectListItem() { Value = Model?.Id > 0 ? Model.Id.ToString() : "", Text = Model?.Id > 0 ? Model.Name : "", Selected = Model?.Id > 0 }}, htmlAttrs) @Html.ValidationMessageFor(model => model.Id, "", new { @class = "text-danger" }) </div> </div> </div>
- 全局注册客户端验证规则
在项目公共js文件中添加对应验证规则,全局生效:
// 注册select2必填验证规则 $.validator.addMethod('select2-required', function (value, element) { return value && value !== "" && value !== "0"; }); $.validator.unobtrusive.adapters.addBool("select2-required");
方案2:自动传递验证规则(低侵入,适合大规模复用)
如果不想在每个调用分部视图的地方手动传错误信息,可以通过自定义模型元数据提供器实现自动将父属性的验证规则传递到子属性Id上:
- 实现自定义元数据提供器
public class Select2RequiredMetadataProvider : IValidationMetadataProvider { public void CreateValidationMetadata(ValidationMetadataProviderContext context) { // 匹配所有实现IId接口的类的Id属性 if (context.Key.Name == nameof(IId.Id) && typeof(IId).IsAssignableFrom(context.Key.ContainerType)) { // 查找父级属性上挂载的Select2RequiredAttribute var parentAttr = context.Attributes.OfType<Select2RequiredAttribute>().FirstOrDefault(); if (parentAttr != null) { // 将父属性的验证规则添加到当前Id属性的验证元数据中 context.ValidationMetadata.ValidatorMetadata.Add(parentAttr); } } } }
- 注册元数据提供器
在Startup.cs的ConfigureServices方法中添加注册:
services.AddMvc(options => { options.ModelMetadataDetailsProviders.Add(new Select2RequiredMetadataProvider()); });
这个方案实现后,你原来的代码不需要做其他修改,只要在父类的复杂属性上标注[Select2Required],对应的子属性Id就会自动继承验证规则,AddValidation方法会正常触发,客户端验证属性会自动生成到输入框上。
内容的提问来源于stack exchange,提问作者Safi Mustafa
相关产品推荐
相关产品推荐

