ASP.NET Core 2 Razor Pages/EF:OnPostAsync设置必填字段无效求助
嘿,我太懂你这个新手坑了——这问题的核心是ModelState的验证在你的OnPostAsync方法执行前就完成了!也就是说,在你手动设置Upload.UploaderID和Upload.Created之前,ASP.NET已经根据页面提交的数据做了一轮验证,所以你后来补的字段值根本没被纳入验证逻辑里,自然会显示ModelState无效。
下面给你几个实用的解决办法,按推荐程度排序:
方法一:手动更新ModelState(最直接的临时方案)
既然你已经在代码里补全了必填字段,那可以在赋值后手动清除对应字段的验证错误,再重新验证整个模型:
public async Task<IActionResult> OnPostAsync() { Upload.Created = DateTime.Now; Upload.UploaderID = _userManager.GetUserId(User); // 清除UploaderID字段的验证错误 ModelState.Remove("Upload.UploaderID"); // 如果Created也是必填项,同样清除它的错误 ModelState.Remove("Upload.Created"); // 重新验证模型 if (!TryValidateModel(Upload)) { return Page(); } _context.Uploads.Add(Upload); await _context.SaveChangesAsync(); return RedirectToPage("./Index"); }
方法二:从Model中移除Required属性(更合理的长期方案)
仔细想想,UploaderID和Created这些字段是服务器端自动赋值的,根本不需要用户输入,所以它们完全没必要加[Required]属性。你可以把这些属性去掉,转而在数据库层面保证非空,既符合逻辑又能避免验证问题:
修改你的Upload模型:
public class Upload { ... // 去掉[Required],因为这个值由服务器自动设置 public String UploaderID { get; set; } [ForeignKey("UploaderID")] public ApplicationUser Uploader { get; set; } // 同样,如果Created是服务器自动生成的,也去掉[Required] public DateTime Created { get; set; } ... }
然后在DbContext的OnModelCreating方法里配置数据库层面的非空约束,确保数据完整性:
protected override void OnModelCreating(ModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); // 数据库层面强制UploaderID非空 modelBuilder.Entity<Upload>() .Property(u => u.UploaderID) .IsRequired(); // 数据库层面强制Created非空 modelBuilder.Entity<Upload>() .Property(u => u.Created) .IsRequired(); }
这种方法更贴合Razor Pages的设计思想,毕竟这些字段不是用户输入的,没必要让ModelState去验证它们。
方法三:使用隐藏字段(不推荐,仅适合特殊场景)
如果你一定要保留Model上的[Required],可以在页面里加隐藏字段提前传入值,但这样存在安全风险(用户可以篡改隐藏字段内容),而且完全没必要——你已经能在服务器端获取用户ID了:
<input type="hidden" asp-for="Upload.UploaderID" value="@User.FindFirstValue(ClaimTypes.NameIdentifier)" /> <input type="hidden" asp-for="Upload.Created" />
还是强烈推荐方法二,既安全又符合规范。
最后再划个重点:ModelState的验证时机在页面方法执行之前,所以你在OnPostAsync里补的字段值不会被自动纳入验证。最合理的做法就是把服务器端自动赋值的字段从Model验证属性中移除,转而用数据库约束保证数据完整性。
内容的提问来源于stack exchange,提问作者Joe Bartlett

