.NET5中如何让ValidationSummary仅显示对应分部视图的验证错误
问题根因
原生asp-validation-summary标签助手默认遍历ModelState字典存储的全量验证错误,不会自动根据当前分部视图绑定的模型层级过滤错误;你当前渲染分部时传入的是全新空ViewDataDictionary,没有携带当前子模型对应的属性路径前缀(HtmlFieldPrefix),最终导致所有分部的验证汇总区域都会展示全页面的所有错误。
实现方案
方案1:自定义支持前缀过滤的ValidationSummary标签助手(推荐,适配多层嵌套分部场景)
该方案可以自动识别当前视图的HtmlFieldPrefix,仅展示前缀匹配的验证错误,完全适配动态渲染、多层分部嵌套的业务场景。
- 编写自定义标签助手代码:
using Microsoft.AspNetCore.Mvc.TagHelpers; using Microsoft.AspNetCore.Mvc.ViewFeatures; using Microsoft.AspNetCore.Razor.TagHelpers; using System.Linq; [HtmlTargetElement("div", Attributes = "asp-partial-validation-summary")] public class PartialValidationSummaryTagHelper : ValidationSummaryTagHelper { public PartialValidationSummaryTagHelper(IHtmlGenerator generator) : base(generator) { } public override void Process(TagHelperContext context, TagHelperOutput output) { var currentPrefix = ViewContext.ViewData.TemplateInfo.HtmlFieldPrefix; if (!string.IsNullOrEmpty(currentPrefix)) { // 筛选当前前缀下的所有验证错误 var matchedKeys = ViewContext.ModelState.Keys .Where(k => k.StartsWith(currentPrefix) || k == string.Empty) .ToList(); var originalModelState = ViewContext.ModelState; var filteredModelState = new ModelStateDictionary(); foreach (var key in matchedKeys) { foreach (var err in originalModelState[key].Errors) { filteredModelState.AddModelError(key, err.ErrorMessage); } } // 用过滤后的ModelState执行原生汇总逻辑,执行完还原原始状态避免影响其他组件 ViewContext.ModelState = filteredModelState; base.Process(context, output); ViewContext.ModelState = originalModelState; } else { base.Process(context, output); } } }
- 在
_ViewImports.cshtml中注册自定义标签助手:
@addTagHelper *, 你的项目程序集名称
- 修正主视图渲染分部的逻辑,给每个分部传入带正确属性前缀的ViewData,不要传空的ViewDataDictionary:
@model Customer <div class="row"> <div class="table-responsive pl-1"> @{ var addressViewData = new ViewDataDictionary(ViewData); // 给Address分部设置对应模型前缀 addressViewData.TemplateInfo.HtmlFieldPrefix = nameof(Model.Address); await Html.RenderPartialAsync("_Address", Model.Address, addressViewData); } </div> <div class="table-responsive pl-1"> @{ var historyViewData = new ViewDataDictionary(ViewData); // 给History分部设置对应模型前缀 historyViewData.TemplateInfo.HtmlFieldPrefix = nameof(Model.History); await Html.RenderPartialAsync("_History", Model.History, historyViewData); } </div> </div>
- 将分部视图中原生的
asp-validation-summary替换为自定义标签即可,参数用法和原生完全一致:传All显示所有匹配错误,传ModelOnly仅显示模型级错误,传None不显示。示例:
<div class="text-danger" asp-partial-validation-summary="All"> </div>
注意:你提供的示例代码中
asp-validation-for存在笔误,City、ZipCode、History板块下的验证指向都写了StreetAddress,需修正为对应属性名,否则字段级行内提示会异常。
方案2:不自定义组件,手动遍历匹配错误渲染汇总
如果不想引入自定义标签助手,可以直接在分部视图中手动拉取当前前缀下的错误渲染汇总,同样需要先按照方案1的步骤给分部设置正确的HtmlFieldPrefix,示例代码:
<div class="text-danger"> <ul> @foreach (var error in ViewContext.ModelState .Where(kv => kv.Key.StartsWith(ViewData.TemplateInfo.HtmlFieldPrefix)) .SelectMany(kv => kv.Value.Errors)) { <li>@error.ErrorMessage</li> } </ul> </div>
嵌套分部适配说明
如果分部视图内部需要继续嵌套下一级分部,只需要在渲染下级分部时,在当前前缀基础上拼接下一级模型的属性名作为新的HtmlFieldPrefix即可,例如Address板块内嵌套邮编子分部,前缀设为$"{ViewData.TemplateInfo.HtmlFieldPrefix}.{nameof(Model.ZipCode)}",自定义标签助手会自动识别当前层级前缀做过滤,无需额外修改逻辑。
内容的提问来源于stack exchange,提问作者flyingniner
相关产品推荐
相关产品推荐

