ASP.NET Core下拉框Required数据注解生效但不显示错误信息
问题描述
我在使用Visual Studio 2019构建项目时遇到一个问题:所有输入字段的Required数据注解能正常阻止未填写的表单提交并显示错误信息,但下拉框组件(SocioId与TipoPlan)仅能阻止提交,却无法显示对应的错误提示。提交空表单时仅能看到一个错误信息。
Controller代码
using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Rendering; using Microsoft.EntityFrameworkCore; using ImprovedWorkCenter.Context; using ImprovedWorkCenter.Models; namespace ImprovedWorkCenter.Controllers { public class PlanController : Controller { private readonly ImprovedWorkCenterContext _context; public PlanController(ImprovedWorkCenterContext context) { _context = context; } // GET: Plan/Create public IActionResult Create() { bool existenSocios = _context.Socios.Count() > 0; if (!existenSocios) { ModelState.AddModelError(String.Empty, "No existen socios para asignar un Plan, cargue uno y vuelva a intentar"); return View(); } var sociosAElegir = from s in _context.Socios select s; ViewBag.SociosActividad = new SelectList(sociosAElegir.ToList(), "SocioId", "Nombre", "Apellido"); return View(); } // POST: Plan/Create // To protect from overposting attacks, enable the specific properties you want to bind to, for // more details, see http://go.microsoft.com/fwlink/?LinkId=317598. [HttpPost] [ValidateAntiForgeryToken] public async Task<IActionResult> Create([Bind("PlanId,SocioId,NombreSocio,Precio,TipoPlan")] Plan plan) { var sociosAElegir = from s in _context.Socios select s; ViewBag.SociosActividad = new SelectList(sociosAElegir.ToList(), "SocioId", "Nombre", "Apellido"); if (ModelState.IsValid) { var socio = await _context.Socios.FindAsync(plan.SocioId); bool existeTipo = _context.Planes.Any(s => s.SocioId == plan.SocioId); if (existeTipo) { ModelState.AddModelError(String.Empty, "El Socio " + socio.Nombre + " " + socio.Apellido + " ya cuenta con un plan."); return View(plan); } bool esDeudor = socio.EsDeudor; if (esDeudor) { ModelState.AddModelError(String.Empty, "No se puede agregar Actividad, el Socio: " + socio.Nombre + " " + socio.Apellido + " es Deudor."); return View(plan); } plan.NombreSocio = socio.Nombre.ToString() + " " + socio.Apellido.ToString(); _context.Add(plan); await _context.SaveChangesAsync(); return RedirectToAction(nameof(Index)); } return View(plan); } } }
Model代码
using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; using System.Linq; using System.Threading.Tasks; namespace ImprovedWorkCenter.Models { public class Plan { [Key] public int PlanId { get; set; } [ForeignKey(nameof(Socio))] [Required(ErrorMessage = "Debe seleccionar un Socio.")] public int SocioId { get; set; } [Display(Name = "Nombre de Socio")] public string NombreSocio { get; set; } [Required(ErrorMessage = "El Precio del plan es obligatorio")] [Range(1, 100000, ErrorMessage = "El Precio debe estar entre {1} y {2} pesos.")] public double Precio { get; set; } [Display(Name = "Tipo de Plan")] [EnumDataType(typeof(TipoPlan))] [Required(ErrorMessage = "El tipo de plan es obligatorio.")] public TipoPlan TipoPlan { get; set; } } }
View代码
@model ImprovedWorkCenter.Models.Plan @{ ViewData["Title"] = "Create"; } <h1>Agregar Plan</h1> <hr /> <div class="row"> <div class="col-md-4"> <form asp-action="Create"> <div asp-validation-summary="ModelOnly" class="text-danger error"></div> @if (ViewBag.SociosActividad != null) { <label asp-for="SocioId" class="control-label"></label> @Html.DropDownList("SocioId", ViewBag.SociosActividad as SelectList, "Selecciones un Socio...", new { @class = "form-control mb-3" }); } <div class="form-group"> <label asp-for="TipoPlan" class="control-label"></label> <select asp-for="TipoPlan" class="form-control" asp-items="Html.GetEnumSelectList<TipoPlan>()"> <option selected="selected" value="">Por favor elija un tipo de Plan</option> <span asp-validation-for="TipoPlan" class="text-danger"></span> </select> </div> <div class="form-group"> <label asp-for="Precio" class="control-label"></label> <input asp-for="Precio" class="form-control" /> <span asp-validation-for="Precio" class="text-danger"></span> </div> <div class="form-group"> <input type="submit" value="Agregar" class="btn btn-primary" /> </div> </form> </div> </div> <div> <a asp-action="Index">Volver</a> </div> @section Scripts { @{await Html.RenderPartialAsync("_ValidationScriptsPartial");} }
解决方案
问题核心是下拉框的验证提示元素位置错误或缺失,导致验证信息无法正常渲染。
1. 修复SocioId下拉框的验证提示
原代码使用@Html.DropDownList且未添加验证提示元素,改为asp-for绑定并补充验证提示:
@if (ViewBag.SociosActividad != null) { <div class="form-group"> <label asp-for="SocioId" class="control-label"></label> <select asp-for="SocioId" class="form-control mb-3" asp-items="@ViewBag.SociosActividad"> <option value="">Selecciones un Socio...</option> </select> <span asp-validation-for="SocioId" class="text-danger"></span> </div> }
2. 修复TipoPlan下拉框的验证提示
原代码将验证提示元素放在<select>标签内部,不符合HTML规范,需移至标签外部:
<div class="form-group"> <label asp-for="TipoPlan" class="control-label"></label> <select asp-for="TipoPlan" class="form-control" asp-items="Html.GetEnumSelectList<TipoPlan>()"> <option value="">Por favor elija un tipo de Plan</option> </select> <span asp-validation-for="TipoPlan" class="text-danger"></span> </div>
可选优化:枚举字段改为可空类型
如果枚举TipoPlan未定义默认空值选项,建议将Model中的TipoPlan字段改为可空枚举,确保空选项能正确触发Required验证:
[Display(Name = "Tipo de Plan")] [EnumDataType(typeof(TipoPlan))] [Required(ErrorMessage = "El tipo de plan es obligatorio.")] public TipoPlan? TipoPlan { get; set; }
完成以上修改后,两个下拉框的Required错误提示即可正常显示。
内容的提问来源于stack exchange,提问作者lgz
相关产品推荐
相关产品推荐

