ASP.NET Core中HTML输入无法绑定到模型的问题求助
问题描述
我正在尝试创建一个Order实体,已经完成了模型、控制器和视图的编写,但在视图中填写所有必填内容后,数据无法传递到Post方法,ModelState.IsValid始终返回false,报错提示「(字段名称) 不能为空」。尝试过创建独立视图模型、更换视图中的@model等方法,卡了两天,求解决。
控制器代码
using FindWorkWeb.DataAccess.Data; using FindWorkWeb.Models.Models; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; using System.ComponentModel.DataAnnotations; namespace FindWorkWeb.Areas.User.Controllers { [Area("User")] public class OrderController : Controller { private readonly UserManager<IdentityUser> _userManager; private readonly ApplicationDbContext _context; public OrderController(UserManager<IdentityUser> userManager, ApplicationDbContext context) { _userManager = userManager; _context = context; } public class InputModel() { [Display(Name = "Title")] public string Title { get; set; } [Display(Name = "Description")] public string Description { get; set; } [Display(Name = "ApproximatedPrice")] public float ApproximatedPrice { get; set; } [Display(Name = "City")] public string City { get; set; } } public InputModel Input { get; set; } [HttpGet] [Authorize] public IActionResult Create() { Input = new InputModel(); return View(Input); } [HttpPost] public async Task<IActionResult> Create(InputModel inputModel) { if (ModelState.IsValid) { var user = await _userManager.GetUserAsync(User); var order = new Order { ApplicationUserId = user.Id, Title = Input.Title, Description = Input.Description, ApproximatedPrice = Input.ApproximatedPrice, City = Input.City, Status = "Pending", PaymentStatus = false }; _context.Orders.Add(order); await _context.SaveChangesAsync(); return RedirectToAction("Index", "Home"); } return View(); } } }
视图代码
@model FindWorkWeb.Areas.User.Controllers.OrderController.InputModel @{ ViewData["Title"] = "Create Order"; } <h1>Create Order</h1> <form asp-action="Create" method="post"> <div class="form-group"> <input asp-for="Title" class="form-control" placeholder="Title"/> @* <span asp-validation-for="InputModel.Title" class="text-danger"></span> *@ </div> <div class="form-group"> <textarea asp-for="Description" class="form-control" placeholder="Description"></textarea> @* <span asp-validation-for="Input.Description" class="text-danger"></span> *@ </div> <div class="form-group"> <input asp-for="ApproximatedPrice" class="form-control" placeholder="Price" /> @* <span asp-validation-for="Input.ApproximatedPrice" class="text-danger"></span> *@ </div> <div class="form-group"> <input asp-for="City" class="form-control" placeholder="City" /> @* <span asp-validation-for="Input.City" class="text-danger"></span> *@ </div> <div class="form-group"> <input type="submit" value="Create" class="btn btn-primary" /> </div> </form> @section Scripts { @{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); } }
解决方案
1. 修正InputModel类定义的语法错误
控制器中嵌套的InputModel类多了多余的括号,这会导致编译异常或模型绑定失败:
// 错误写法 public class InputModel() // 正确写法 public class InputModel
2. Post方法中使用传入的inputModel参数
控制器的Input是实例属性,Post请求会生成全新的控制器实例,此时Input未被赋值,始终为默认值。正确的做法是使用Post方法接收的inputModel参数来构建Order实体:
var order = new Order { ApplicationUserId = user.Id, Title = inputModel.Title, Description = inputModel.Description, ApproximatedPrice = inputModel.ApproximatedPrice, City = inputModel.City, Status = "Pending", PaymentStatus = false };
3. 验证失败时返回带模型的View
当ModelState.IsValid为false时,必须将接收的inputModel传递回视图,否则视图会使用空模型,导致用户输入的内容丢失,且验证提示不准确:
// 错误代码 return View(); // 正确代码 return View(inputModel);
4. 启用视图中的验证提示
取消视图中验证提示的注释,并修正asp-validation-for的目标(直接使用属性名,无需前缀),方便查看具体的验证错误:
<span asp-validation-for="Title" class="text-danger"></span> <span asp-validation-for="Description" class="text-danger"></span> <span asp-validation-for="ApproximatedPrice" class="text-danger"></span> <span asp-validation-for="City" class="text-danger"></span>
5. (可选)将InputModel提取为独立类
把嵌套在控制器中的InputModel移到单独的ViewModels文件夹下,代码结构更清晰,也避免视图引用控制器内部类的复杂路径:
namespace FindWorkWeb.ViewModels.User { public class OrderInputModel { [Display(Name = "Title")] [Required(ErrorMessage = "标题不能为空")] public string Title { get; set; } [Display(Name = "Description")] [Required(ErrorMessage = "描述不能为空")] public string Description { get; set; } [Display(Name = "ApproximatedPrice")] [Range(0.01, double.MaxValue, ErrorMessage = "价格必须大于0")] public float ApproximatedPrice { get; set; } [Display(Name = "City")] [Required(ErrorMessage = "城市不能为空")] public string City { get; set; } } }
之后控制器和视图只需引用这个独立类即可。
内容的提问来源于stack exchange,提问作者Ulad Shuhayeu
相关产品推荐
相关产品推荐

