ASP.NET控制器传值到视图回传时其余字段为null如何解决
HTTP表单提交只会发送<form>标签内部带name属性的有效输入控件的值,你当前表单中仅存在绑定Name属性的输入框,Id、Cas、Room字段没有任何对应的表单项,提交请求时不会携带这三个字段的值,后端模型绑定自然无法给这几个字段赋值,和POST Action中[Bind]特性的白名单配置无关。
另外你的form标签存在笔误:多写了一个空的asp-属性,会影响ASP.NET Core标签助手的正常渲染,需要删除。
额外注意:Room是自定义复杂引用类型,即使你添加<input type="hidden" asp-for="Room" />也无法完成绑定,模型绑定器需要匹配Room.属性名格式的多个值才能填充复杂类型对象。
你可以根据数据安全需求,选择以下两种方案:
方案1:添加隐藏域传递非编辑字段(适合非敏感数据)
在表单内部为不需要用户编辑、需要回传的字段添加隐藏输入框,复杂类型Room建议通过外键ID传递,不要直接传递整个对象。
- 建议先给
ReservationModel补充外键字段(如果尚未定义):
public class ReservationModel { [Key] public int Id { get; set; } public string Name { get; set; } public DateTime Cas { get; set; } // 新增关联Room的外键 public int RoomId { get; set; } public RoomModel Room { get; set; } }
如果你不想加外键,也可以为Room的每个需要保留的属性单独加隐藏域,比如<input type="hidden" asp-for="Room.Id" />,但这种方式繁琐易漏字段,不推荐。
2. 修改视图代码,添加对应隐藏域,删除无效的asp-笔误:
@model ReservationModel <form asp-controller="Home" asp-action="CreateReservation" method="post"> <!-- 隐藏域回传非编辑字段 --> <input type="hidden" asp-for="Id" /> <input type="hidden" asp-for="Cas" /> <input type="hidden" asp-for="RoomId" /> <input required="required" type="text" class="form-control scan" placeholder="Name" asp-for="Name" /> <span asp-validation-for="Name" class="text-danger"></span> <input type="submit" class="model-close button btn btn-primary primary-btn" style="width:auto;" value="Add" /> </form>
- 对应修改POST Action的
[Bind]白名单,加入RoomId,移除无法直接绑定的Room:
[HttpPost] [Route("Home/Room/Create_reservation")] public async Task<IActionResult> CreateReservation([Bind("Name","RoomId","Cas","Id")] ReservationModel reservationModel) { if (!ModelState.IsValid) { // 校验不通过时返回视图,需要将模型传回 return View(reservationModel); } // 根据RoomId查询对应Room对象,赋值给reservationModel.Room后执行保存逻辑 return RedirectToAction("Index"); }
注意:隐藏域的值可以被用户通过浏览器开发者工具随意篡改,POST接口必须做合法性校验,比如校验当前用户是否有权限操作对应ID的预约、RoomId是否合法、Cas时间是否在允许预约范围内,避免越权操作。
方案2:后端重新查询关联数据(适合敏感字段,安全性更高)
如果Id、Cas、Room属于不希望被用户篡改的敏感数据,就不要把这些值放到前端,提交时只传用户输入的Name字段,后端根据上下文重新查询原始数据再合并:
- GET Action中将需要保留的唯一标识存入
TempData(支持跨单次请求传递):
[HttpGet] [Route("Home/Room/Create_reservation")] public async Task<IActionResult> CreateReservation(DateTime date) { ReservationModel reservation = await _reservation.PrepareModel(date, _id); // 存储原始数据标识 TempData["ReservationId"] = reservation.Id; TempData["ReservationCas"] = reservation.Cas.ToString("o"); // 日期用ISO标准格式序列化 TempData["RoomId"] = reservation.Room.Id; return View(reservation); }
- 视图不需要加任何隐藏域,仅保留Name输入框即可,记得删除form标签中无效的
asp-笔误。 - POST Action中仅接收Name字段,从TempData取出原始标识组装完整模型:
[HttpPost] [Route("Home/Room/Create_reservation")] public async Task<IActionResult> CreateReservation(string Name) { // 校验TempData中的原始标识是否合法 if (!int.TryParse(TempData["ReservationId"]?.ToString(), out int resId) || !DateTime.TryParse(TempData["ReservationCas"]?.ToString(), out DateTime cas) || !int.TryParse(TempData["RoomId"]?.ToString(), out int roomId)) { // 数据过期或非法时重定向到预约入口 return RedirectToAction("Index"); } // 查询关联的Room信息 var room = await _dbContext.Rooms.FindAsync(roomId); var reservationModel = new ReservationModel { Id = resId, Cas = cas, Room = room, Name = Name }; // 执行校验、保存逻辑 return RedirectToAction("Success"); }
该方案完全避免了前端篡改敏感字段的风险,适合数据安全要求高的场景。
内容的提问来源于stack exchange,提问作者fikus

