.NET 6 ASP.NET Core自定义ModelError后asp-validation不显示
问题现象
.NET 6 ASP.NET Core项目中,POST接口校验失败后通过TempData传递错误标识,重定向到GET动作后手动添加ModelState自定义错误,无论使用asp-validation-summary标签还是@Html.ValidationMessage("CustomError")都无法渲染错误提示,同项目其他页面的自定义ModelState错误可正常生效。
相关核心代码片段:
- 添加自定义模型错误代码:
ModelState.AddModelError("CustomError", "Sorry, it looks like the submission did not go through.");
- 原验证错误渲染代码:
<div asp-validation-summary="All" class="text-danger border m-3"></div>
业务流程
- POST接口
birdData校验传入的鸟类环码不存在时,通过TempData存储错误标识后重定向到ShowBirdLocations动作 ShowBirdLocationsGET动作读取TempData中的错误标识,匹配后添加自定义ModelState错误并返回视图- 当前视图已注释
asp-validation-summary代码,尝试使用@Html.ValidationMessage("CustomError")单独渲染自定义错误,仍无法显示提示
根因分析
核心问题是接口调用方式和后端返回逻辑不匹配:
- 页面上的提交按钮是通过前端
fetch发异步请求调用birdData接口,不是传统表单同步提交 - 异步请求场景下,后端返回的
RedirectToAction不会触发浏览器页面跳转:fetch内核会自动跟随重定向请求GET接口,最终拿到重定向后的完整页面HTML,但前端代码写死了return response.json(),会直接尝试把HTML解析为JSON并抛出脚本错误,既不会替换当前页面内容,也不会触发任何提示 - 用户始终停留在首次加载的
ShowBirdLocations页面,首次GET请求时TempData中没有错误标识,自然不会添加ModelState错误,提示永远无法显示
修复方案
二选一即可:
方案1:适配异步交互逻辑,接口返回JSON错误
废弃TempData+重定向的逻辑,接口直接返回结构化错误,前端负责渲染提示:
- 修改POST接口错误分支,直接返回400错误JSON
if (check == false) { return BadRequest(new { error = "Sorry, it looks like the submission did not go through." }); }
- 视图中增加固定的错误提示容器
<div id="errorTip" class="text-danger border m-3 d-none"></div>
- 修改前端fetch逻辑,增加错误捕获分支
async function postData(url = '', data = {}) { const response = await fetch(url, { method: 'post', headers: { 'Content-Type': 'application/json', 'data': JSON.stringify(data) } }); if (!response.ok) { const errRes = await response.json(); throw new Error(errRes.error); } return response.json(); } fetchButton.addEventListener("click", function () { const errorTip = document.getElementById("errorTip"); // 每次请求前清空旧错误 errorTip.classList.add("d-none"); errorTip.textContent = ""; postData(url, { ringCode: fetchInput.value }) .then(data => { // 原有成功逻辑保持不变 for (let i = 0; i < data.birdData.length; i++) { if (data.birdData[i].gridRef != null) { data.birdData[i].latitude = getLat(data.birdData[i].gridRef); data.birdData[i].longitude = getLng(data.birdData[i].gridRef); } } var url1 = "/results/generateSearchResult"; var asd = url1 + "?test=" + JSON.stringify(data); window.location = asd; }) .catch(err => { // 显示接口返回的错误 errorTip.textContent = err.message; errorTip.classList.remove("d-none"); }) });
方案2:改回传统表单同步提交
如果不想写前端错误处理逻辑,去掉fetch异步提交代码,将输入框、按钮包裹在form标签内,设置form的action为birdData、method为post,走传统MVC表单提交流程。
这种方案下需要给TempData加保留标记,避免跨请求读取后被自动清除:
public IActionResult ShowBirdLocations() { var err = TempData["WrongRingCodeErrorMessage"] as String; if(err == "Error message") { TempData.Keep("WrongRingCodeErrorMessage"); ModelState.AddModelError("CustomError", "Sorry, it looks like the submission did not go through."); } return View(); }
改完后无论是asp-validation-summary还是单独的@Html.ValidationMessage("CustomError")都能正常渲染错误。
额外优化建议
当前代码把请求参数放在自定义data请求头中传递,不符合常规接口传参规范,建议后续调整为从请求Body读取参数,避免遇到请求头长度限制、网关拦截等兼容问题。
内容的提问来源于stack exchange,提问作者BUIBBE
相关产品推荐
相关产品推荐

