ASP.NET Core MVC模态框验证异常:自定义验证触发后跳转无格式页面
ASP.NET Core MVC 模态弹窗自定义验证跳转问题
开发小型ASP.NET Core MVC应用时遇到数据验证异常:通过模态弹窗录入数据,模型自带的必填、长度校验可正常在弹窗内显示错误提示;但执行重复数据的自定义验证时,页面会跳转到无格式的非模态页面,无法在弹窗内展示错误信息。
模型类
[Key] public int IDArbitro { get; set; } [Column(TypeName = "varchar(50)")] [Display(Name = "Apellidos")] [Required(ErrorMessage = "Los apellidos son obligatorios")] [StringLength(50, ErrorMessage = "El campo {0} no debe exceder de {1} caracteres.")] public string Apellidos { get; set; } [Column(TypeName = "varchar(20)")] [Display(Name = "Nombre")] [Required(ErrorMessage = "El nombre es obligatorio")] [StringLength(50, ErrorMessage = "El campo {0} no debe exceder de {1} caracteres.")] public string Nombre { get; set; }
控制器
[HttpGet] public IActionResult InsertOrUpdate(int id) { Arbitro arbitro = new Arbitro(); if (id > 0) { arbitro = _context.Arbitros.Where(x => x.IDArbitro == id).SingleOrDefault(); } return PartialView("InsertOrUpdate", arbitro); } [HttpPost] [ValidateAntiForgeryToken] public IActionResult InsertOrUpdate(Arbitro arbitro) { if (ModelState.IsValid) { if (ValidarDatos(arbitro)) { if (arbitro.IDArbitro == 0) { _context.Arbitros.Add(arbitro); } else { _context.Arbitros.Update(arbitro); } _context.SaveChanges(); return RedirectToAction("List", "Arbitro"); } else { return PartialView("InsertOrUpdate", arbitro); } } else { return PartialView("InsertOrUpdate", arbitro); } } private bool ValidarDatos(Arbitro arbitro) { bool isOK = true; if (_context.Arbitros.Any(x => x.Nombre == arbitro.Nombre && x.Apellidos == arbitro.Apellidos && x.IDArbitro != arbitro.IDArbitro)) { ModelState.AddModelError(string.Empty, $"Ya existe un arbitro con el nombre {arbitro.Nombre} y los apellidos {arbitro.Apellidos}"); isOK = false; } return isOK; }
视图
@model FootballStats.Models.Arbitro @{ ViewData["Title"] = "Modificar"; } <script src="~/lib/jquery/dist/jquery.min.js"></script> <script src="~/lib/jquery-validation/dist/jquery.validate.min.js"></script> <script src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js"></script> <div class="modal fade" id="insertOrUpdateModal" tabindex="-1" role="dialog" aria-labelledby="insertOrUpdateModalLabel" aria-hidden="true"> <div class="modal-dialog" role="document"> <div class="modal-content"> <div class="modal-header bg-dark"> @if (@Model.IDArbitro == 0) { <h3 class="text-white"><strong>Añadir árbitro</strong></h3> } else { <h3 class="text-white"><strong>Modificar árbitro</strong></h3> } </div> <form asp-controller="Arbitro" asp-action="InsertOrUpdate" data-ajax-method="POST"> <div class="modal-body"> <input type="hidden" asp-for="IDArbitro" /> <div class="mb-2"> <label class="form-label">Nombre</label> <input class="form-control form-control sm" asp-for="Nombre" type="text" /> <!--<span asp-validation-for="Nombre" class="text-danger"></span> <p style="color:#FF0000" ;>@Html.ValidationMessageFor(m => m.Nombre)</p>--> </div> <div class="mb-2"> <label class="form-label">Apellidos</label> <input class="form-control form-control sm" asp-for="Apellidos" type="text" /> </div> @Html.ValidationSummary(false, "", new { @class = "text-danger" }) </div> <div class="modal-footer"> <button class="btn btn-primary" type="submit">Guardar</button> <button type="button" class="btn btn-dark" data-bs-dismiss="modal">Cancelar</button> </div> </form> </div> </div> </div> @section Scripts { @{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); } }
问题根源
表单仅添加了data-ajax-method="POST"但未启用Unobtrusive AJAX提交机制,导致:
- 客户端验证(模型特性校验)通过jQuery Validation正常工作,无需提交到服务器
- 服务器端自定义验证失败时,表单以普通提交方式返回PartialView,浏览器直接渲染该局部视图,出现无格式页面
解决方案
1. 安装Unobtrusive AJAX包
通过NuGet安装Microsoft.jQuery.Unobtrusive.Ajax:
Install-Package Microsoft.jQuery.Unobtrusive.Ajax
2. 引入Unobtrusive AJAX脚本
在视图中添加脚本引用(放在jQuery和Validation脚本之后):
<script src="~/lib/jquery-ajax-unobtrusive/jquery.unobtrusive-ajax.min.js"></script>
3. 修改表单AJAX配置
更新表单属性,启用AJAX提交并指定内容替换目标:
<form asp-controller="Arbitro" asp-action="InsertOrUpdate" data-ajax="true" data-ajax-method="POST" data-ajax-update="#insertOrUpdateModal .modal-content" data-ajax-success="function() { if ($('#insertOrUpdateModal .text-danger').length === 0) { $('#insertOrUpdateModal').modal('hide'); location.reload(); } }">
data-ajax="true":启用Unobtrusive AJAX提交data-ajax-update:指定服务器返回的PartialView替换弹窗内的.modal-content区域,确保错误信息留在弹窗中data-ajax-success:验证通过时关闭弹窗并刷新列表页面
4. 完善验证消息显示
恢复输入框的验证消息标签,确保客户端验证提示正常显示:
<div class="mb-2"> <label class="form-label">Nombre</label> <input class="form-control form-control-sm" asp-for="Nombre" type="text" /> <span asp-validation-for="Nombre" class="text-danger"></span> </div> <div class="mb-2"> <label class="form-label">Apellidos</label> <input class="form-control form-control-sm" asp-for="Apellidos" type="text" /> <span asp-validation-for="Apellidos" class="text-danger"></span> </div>
内容的提问来源于stack exchange,提问作者Thorbadin
相关产品推荐
相关产品推荐

