ASP.NET Core中如何在局部视图回显表单错误与未完成数据?
解决方案:表单验证失败时保留输入并返回原页面
你遇到的这个问题是局部视图处理表单提交时的典型痛点——因为没有独立的CreateNote视图,验证失败后需要回到Details页面,同时还要保留用户已经输入的内容和验证错误提示。之前尝试的RedirectToAction会导致所有临时数据丢失,而视图的Model只读也限制了直接修改的可能,下面给你一套可行的解决方案:
1. 修改CreateNote控制器方法,直接返回Details视图而不是重定向
重定向(RedirectToAction)会触发新的GET请求,之前的表单数据和ModelState都会被清空,所以我们需要服务器端直接返回Details视图,把验证失败的草稿数据和错误状态一并传递过去:
[HttpPost] [ValidateAntiForgeryToken] public async Task<IActionResult> CreateNote(int projectId, [Bind("Title,Contents")] ProjectNote note) { Project project = await db.Projects .Include(n => n.Notes) .Include(p => p.ParentProject) .Include(c => c.ChildProjects) .ThenInclude(o => o.ProjectOwner) .Include(o => o.ProjectOwner) .FirstOrDefaultAsync(p => p.Id == projectId); if (project == null) { return NotFound(); } if (project.Completed) { return RedirectToAction("Details", new { id = project.Id }); } note.ProjectId = projectId; note.Created = DateTime.Now; if (ModelState.IsValid) { db.Add(note); await db.SaveChangesAsync(); return RedirectToAction("Details", new { id = projectId }); } // 验证失败:构建Details页面的ViewModel,携带草稿数据 ProjectViewModel vm = auto.Map<ProjectViewModel>(project); vm.ProjectNoteAction = "c"; // 保持创建模式激活状态 vm.DraftNote = auto.Map<ProjectNoteViewModel>(note); // 存储用户输入的草稿 // 保留ModelState错误,让前端验证提示正常显示 return View("Details", vm); }
2. 扩展ProjectViewModel,新增草稿数据属性
在你的ProjectViewModel中添加一个属性,用来存储验证失败的笔记草稿:
public ProjectNoteViewModel DraftNote { get; set; }
3. 调整主视图Details.cshtml,传递草稿数据到局部视图
修改渲染_notes局部视图的代码,把草稿数据传递过去:
<partial name="_notes" model="@new ProjectNotesViewModel { ProjectId = Model.Id, Notes = Model.Notes, ProjectNoteId = Model.ProjectNoteId, ProjectNoteAction = Model.ProjectNoteAction, ProjectCompleted = Model.Completed, DraftNote = Model.DraftNote // 传递草稿数据 }" />
4. 更新_notes局部视图,渲染带草稿的创建表单
在_notes.cshtml中添加创建模式的渲染逻辑,优先使用草稿数据填充表单:
@* 先渲染创建模式的表单 *@ @if (Model.ProjectNoteAction == "c") { <tr class="alert-black-50"> <td class="align-text-top text-light rounded-left" width="1"> <span class="fas fa-clipboard fa-fw"></span> </td> <td class="pb-2 pr-2 text-light rounded-right"> @* 如果有草稿就用草稿数据,否则用空模型 *@ <partial name="_noteCreate" model="@(Model.DraftNote ?? new ProjectNoteViewModel { ProjectId = Model.ProjectId })" /> </td> </tr> } @* 原有的笔记列表渲染逻辑 *@ @foreach (ProjectNoteViewModel note in Model.Notes) { // 你的原有代码... }
备选方案:用TempData实现重定向后保留数据(适合必须重定向的场景)
如果业务上必须用RedirectToAction,可以把草稿数据序列化后存入TempData(短期会话存储):
// 在CreateNote方法的验证失败分支 var draftVm = auto.Map<ProjectNoteViewModel>(note); TempData["DraftNote"] = JsonSerializer.Serialize(draftVm); // 同时存储ModelState错误 var errorDict = ModelState.ToDictionary(kv => kv.Key, kv => kv.Value.Errors.Select(e => e.ErrorMessage).ToList()); TempData["ModelStateErrors"] = JsonSerializer.Serialize(errorDict); return RedirectToAction("Details", new { id = projectId, a = "c" });
然后在Details控制器方法中读取TempData并恢复数据:
public async Task<IActionResult> Details(int? id, int n, string a) { // 原有的查询逻辑... ProjectViewModel vm = auto.Map<ProjectViewModel>(project); // 读取TempData中的草稿和错误 if (TempData.ContainsKey("DraftNote")) { vm.DraftNote = JsonSerializer.Deserialize<ProjectNoteViewModel>(TempData["DraftNote"].ToString()); var errors = JsonSerializer.Deserialize<Dictionary<string, List<string>>>(TempData["ModelStateErrors"].ToString()); foreach (var error in errors) { foreach (var message in error.Value) { ModelState.AddModelError(error.Key, message); } } } vm.ProjectNoteAction = a; // ...其他赋值逻辑 return View(vm); }
核心原理说明
- 直接返回
Details视图:服务器端直接渲染页面,能保留ModelState错误和草稿数据,不需要客户端重新发起请求 - 扩展ViewModel传递草稿:通过ViewModel的属性把数据从控制器传递到各级局部视图,避开视图Model只读的限制
- 保留ModelState:确保前端的
asp-validation-summary和asp-validation-for能正常显示错误提示
内容的提问来源于stack exchange,提问作者Stian
相关产品推荐
相关产品推荐

