You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 15:56:01