ASP.NET Core MVC中Inventory.cshtml无法与控制器及模型交互求助
我在ASP.NET Core MVC项目里,Inventory.cshtml视图没法接收或发送数据到控制器和模型。已经排查了拼写、命名空间这类可能的错误,但控制台和终端都没报错,根本找不到问题所在。核心问题是:Inventory.cshtml收不到来自模型和控制器的错误提示或消息。
注:项目用了Shared文件夹下的_DashboardLayout和_Layout两种布局,不确定会不会影响。
相关代码
实体类Product.cs
using System.ComponentModel.DataAnnotations; namespace SportsCapstone.Entities { public class Product { [Key] public int Id { get; set; } // public byte[] Image { get; set; } // Storing image as byte array [Required(ErrorMessage = "Product is required.")] [MaxLength(20, ErrorMessage = "Max 20 characters allowed")] public string ProductName { get; set; } [Required(ErrorMessage = "Brand is required.")] [MaxLength(20, ErrorMessage = "Max 20 characters allowed")] public string ProductBrand { get; set; } [Required(ErrorMessage = "Quantity should not be empty")] [Range(1, int.MaxValue, ErrorMessage = "Quantity Must be atleast 1.")] public int Quantity { get; set; } [Required(ErrorMessage = "Type of Product is required.")] [MaxLength(20, ErrorMessage = "Max 20 characters allowed")] public string TypeOfProduct { get; set; } [Required(ErrorMessage = "Type of Age is required.")] [Range(1, 60, ErrorMessage = "Age should not be more than 60")] public string AgeRange { get; set; } } }
模型类InventoryItem.cs
using System.ComponentModel.DataAnnotations; namespace SportsCapstone.Models { public class InventoryItem { [Required(ErrorMessage = "Product name is required.")] [MaxLength(20, ErrorMessage = "Max 20 characters allowed.")] public string ProductName { get; set; } [Required(ErrorMessage = "Product brand is required.")] [MaxLength(20, ErrorMessage = "Max 20 characters allowed.")] public string ProductBrand { get; set; } [Required(ErrorMessage = "Quantity is required.")] [Range(1, int.MaxValue, ErrorMessage = "Quantity must be a positive number.")] public int Quantity { get; set; } // Changed to int [Required(ErrorMessage = "Type of product is required.")] [MaxLength(20, ErrorMessage = "Max 20 characters allowed.")] public string TypeOfProduct { get; set; } [Required(ErrorMessage = "Age range is required.")] [Range(5, 20, ErrorMessage = "Age range must be between 5 and 20.")] public string AgeRange { get; set; } // [Required(ErrorMessage = "Image is required.")] // public IFormFile Image { get; set; } // For file uploads } }
控制器InventoryController.cs
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using SportsCapstone.Models; // This should be your models namespace using SportsCapstone.Entities; // Keep if you need to reference Product using Microsoft.EntityFrameworkCore; namespace SportsCapstone.Controllers // Corrected namespace { [Authorize] public class InventoryController : Controller { private readonly AppDbContext _dbContext; public InventoryController(AppDbContext appDbContext) { _dbContext = appDbContext; } public IActionResult Inventory() { return View(); } [HttpPost] [ValidateAntiForgeryToken] public IActionResult Inventory(InventoryItem model) // Change to InventoryItem { if (ModelState.IsValid) { // If needed, convert InventoryItem to Product here Product product = new Product { ProductName = model.ProductName, ProductBrand = model.ProductBrand, Quantity = model.Quantity, TypeOfProduct = model.TypeOfProduct, AgeRange = model.AgeRange }; try { _dbContext.Products.Add(product); _dbContext.SaveChanges(); ModelState.Clear(); ViewBag.Message = $"{product.ProductName} registered successfully. Please Login."; } catch (DbUpdateException) { ModelState.AddModelError("", "Please enter a unique Email or Password."); return View(model); } return View(); } return View("Inventory", model); //return model with correct view name } } }
视图Inventory.cshtml(关键部分)
@model SportsCapstone.Models.InventoryItem @{ Layout = "_DashboardLayout"; } ... @if (ViewBag.Message != null) { <div class="d-flex align-items-center justify-content-center w-100" style="color: green"> @ViewBag.Message </div> } <form asp-controller="Inventory" asp-action="Create" method="post" class="inv-cp-ppqty"> <div class="image"> <label for="imageUpload"> <svg id="imageLabel" width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg"> </svg> <img id="imagePreview" style="display: none; max-width: 100%; height:100%; object-fit: cover; border-radius: 10px;" /> </label> @* <input asp-for="Image" type="file" id="imageUpload" name="Image" required onchange="previewImage(event)" /> *@ @* <span asp-validation-for="Image" class="text-danger"></span> *@ @* <img src="" alt=""> *@ </div> <div class="fill-inv"> <div class="inp-inv"> <input asp-for="ProductName" type="text" placeholder="Product Name" /> <span asp-validation-for="ProductName" class="text-danger"></span> </div> <div class="inp-inv"> <input asp-for="ProductBrand" type="text" placeholder="Product Brand" /> <span asp-validation-for="ProductBrand" class="text-danger"></span> </div> <div class="inp-inv"> <input asp-for="Quantity" type="number" placeholder="Quantity" min="1" /> <span asp-validation-for="Quantity" class="text-danger"></span> </div> <div class="inp-inv"> <select asp-for="TypeOfProduct" id="typeOfProduct" class="form-control"> <option value="" disabled selected> Type of Product </option> <option value="Cloth"> Cloth </option> <option value="Pants"> Pants </option> <option value="Accessories"> Accessories </option> <option value="SportsGear"> Sports Gear </option> <!-- Add more options as needed --> </select> <span asp-validation-for="TypeOfProduct" class="text-danger"></span> </div> <div class="inp-inv"> <select asp-for="AgeRange" id="ageRange" class="form-control"> <option value="" disabled selected> Age </option> <option value="Kids"> -18 </option> <option value="Adults"> 18+ </option> <!-- Add more options as needed --> </select> <span asp-validation-for="AgeRange" class="text-danger"></span> </div> <button type="submit" class="button-type"> <h5> Create Item </h5> </button> </div> </form>
问题排查与修复方案
1. 表单Action匹配错误
视图表单指定了asp-action="Create",但控制器中只有名为Inventory的Post方法,不存在Create方法,导致表单提交后找不到对应Action,无任何反馈。
修复:将表单的asp-action改为"Inventory":
<form asp-controller="Inventory" asp-action="Inventory" method="post" class="inv-cp-ppqty">
2. 字符串属性错误使用Range验证
Product和InventoryItem中的AgeRange是字符串类型,但都添加了仅适用于数值类型的[Range]注解,导致验证逻辑失效,甚至引发隐性模型绑定错误。
修复:移除字符串属性上的[Range]注解,若需限制取值范围,改用[RegularExpression]:
// 修改InventoryItem.cs的AgeRange属性 [Required(ErrorMessage = "Age range is required.")] [RegularExpression(@"^(Kids|Adults)$", ErrorMessage = "Age range must be 'Kids' or 'Adults'")] public string AgeRange { get; set; } // 修改Product.cs的AgeRange属性 [Required(ErrorMessage = "Type of Age is required.")] public string AgeRange { get; set; }
3. 保存成功后错误清空ModelState
控制器中保存成功后调用ModelState.Clear(),会清空所有模型状态,且返回无模型的View(),导致视图无法获取输入值或错误信息。同时使用ViewBag传递消息易丢失,推荐用PRG模式防止重复提交。
修复:保存成功后重定向到Get方法,用TempData传递消息:
try { _dbContext.Products.Add(product); _dbContext.SaveChanges(); TempData["Message"] = $"{product.ProductName} registered successfully."; return RedirectToAction(nameof(Inventory)); } catch (DbUpdateException) { ModelState.AddModelError("", "保存失败,请检查输入是否合法或重复。"); return View(model); }
视图中修改消息显示逻辑:
@if (TempData["Message"] != null) { <div class="d-flex align-items-center justify-content-center w-100" style="color: green"> @TempData["Message"] </div> }
4. Get方法未传递空模型
控制器的Get方法Inventory()直接返回View(),未传递空的InventoryItem模型,可能导致asp-for标签无法正确生成name属性,影响模型绑定。
修复:返回带空模型的视图:
public IActionResult Inventory() { return View(new InventoryItem()); }
5. 布局页缺失验证脚本
若_DashboardLayout未引用ASP.NET Core客户端验证脚本,会导致客户端验证失效,服务器端错误也可能无法正常显示。
修复:在布局页</body>前添加验证脚本:
<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>
内容的提问来源于stack exchange,提问作者Leonhard Meinhard

