ASP.NET MVC中POST请求后ViewModel变为空的问题
编辑用户角色页面空引用异常解决
问题情况
开发修改用户现有角色名称的编辑页面时,发送POST请求后Edit页面的ViewModel变为空(已断点验证),随后Visual Studio抛出异常:
System.NullReferenceException: 'Object reference not set to an instance of an object.'
Microsoft.AspNetCore.Mvc.Razor.RazorPage.Model.get returned null.
问题根源
- 异常返回时未传递ViewModel:POST方法的catch块中直接
return View(),没有给页面传入任何模型,导致Razor页面的Model为null,渲染时访问Model.User触发空引用异常。 - 手动解析表单易出错:使用
IFormCollection接收表单字段,不仅需要手动解析,还不利于代码维护和模型验证。
解决办法
紧急修复:异常时传递ViewModel
修改UserController.cs的POST Edit方法,在catch块中重新构建ViewModel并传入:
[HttpPost] public async Task<IActionResult> Edit(string principalId, IFormCollection formCollection) { try { await _userControllerService.EditAzureUser(formCollection); return RedirectToAction(nameof(Index)); } catch { // 重新获取用户数据填充ViewModel,需实现根据ID查询用户的逻辑 var viewModel = new CreateUserViewModel(); viewModel.User = await _userService.GetUserById(principalId); // 回填用户已选择的角色,避免重复操作 viewModel.User.AppRoleName = formCollection["User.AppRoleName"]; return View(viewModel); } }
优化方案:改用强类型模型绑定(推荐)
直接使用ViewModel接收表单,利用ASP.NET自动模型绑定功能,减少手动解析的错误,同时支持模型验证。
- 更新
UserController.cs:
[HttpPost] public async Task<IActionResult> Edit(CreateUserViewModel model) { if (!ModelState.IsValid) { return View(model); } try { await _userControllerService.EditAzureUser(model); return RedirectToAction(nameof(Index)); } catch { ModelState.AddModelError("", "编辑角色失败,请重试"); return View(model); } }
- 调整
UserControllerService.cs参数:
public async Task EditAzureUser(CreateUserViewModel model) { string id = model.User.PrincipalId; string appRoleId = model.User.AppRoleId; string newRoleName = model.User.AppRoleName; // 此处编写编辑逻辑,例如根据角色名称获取对应ID并更新用户 }
- 优化
Edit.cshtml(添加表单标签,简化选项判断):
@model CreateUserViewModel @{ ViewData["Title"] = "Edit User"; } <form asp-action="Edit"> <label asp-for="User.PrincipalDisplayName" class="col-form-label">Name: </label> <input asp-for="User.PrincipalDisplayName" readonly class="form-control"/> <label asp-for="User.AppRoleName" class="col-form-label">Role: </label> <select asp-for="User.AppRoleName" title="Select Role" required class="form-control" style="margin-bottom: 1rem"> @foreach(var role in AppRole.Roles) { <option value="@role" @(Model.User.AppRoleName == role ? "selected" : "")>@role</option> } </select> <input type="hidden" asp-for="User.PrincipalId"/> <input type="hidden" asp-for="User.AppRoleId"/> <input type="button" value="Cancel" class="btn btn-secondary btn-sm" onclick="history.back()" /> <input type="submit" class="btn btn-info btn-sm" /> </form>
关键注意点
- 表单必须用
<form asp-action="Edit">包裹,否则POST请求无法正确提交到对应控制器方法。 - 任何返回Edit页面的场景(验证失败、异常)都必须传递ViewModel,不能空返回。
- 强类型模型绑定能自动处理表单值映射,还可结合
ModelState实现前端验证,提升用户体验和代码可维护性。
内容的提问来源于stack exchange,提问作者Rick-manak
相关产品推荐
相关产品推荐

