You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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.

问题根源

  1. 异常返回时未传递ViewModel:POST方法的catch块中直接return View(),没有给页面传入任何模型,导致Razor页面的Model为null,渲染时访问Model.User触发空引用异常。
  2. 手动解析表单易出错:使用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自动模型绑定功能,减少手动解析的错误,同时支持模型验证。

  1. 更新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);
    }
}
  1. 调整UserControllerService.cs参数:
public async Task EditAzureUser(CreateUserViewModel model)
{
    string id = model.User.PrincipalId;
    string appRoleId = model.User.AppRoleId;
    string newRoleName = model.User.AppRoleName;
    // 此处编写编辑逻辑,例如根据角色名称获取对应ID并更新用户
}
  1. 优化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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 19:31:09