.NET Core模型值无法回传至视图的问题排查求助
问题背景
在.NET Core应用中开发了带文本输入框和提交按钮的表单,需求是提交后输入框文本能回显在表单内。流程为视图数据传递至控制器动作,再由控制器将值返回至视图。测试发现:输入的值可成功绑定到控制器的模型,但返回视图时值被清空,且触发“Object reference set to null”空引用异常。
相关代码
视图代码
@page @model Models.StringModel <div class="text-left"> <form asp-controller="Home" asp-action="Alter"> <span class="form-control"> <label asp-for="Name">Alter string:</label> @if (@Model != null) { <input type="text" asp-for="Name" class="changeString" value="@Model.Name"/> } else { <input type="text" asp-for="Name" class="changeString"/> } <input class="btn btn-primary" type="submit" value="Update" action="Update" /> </span> </form> </div>
StringModel.cs代码
using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; namespace SplitString.Models { public class StringModel { public int ID { get; set; } public string Name { get; set; } } }
HomeController.cs代码
using Microsoft.AspNetCore.Mvc; using SplitString.Models; using System.Threading.Tasks; namespace SplitString.Controllers { public class HomeController : Controller { public IActionResult Index() { return View(); } [HttpPost] [ValidateAntiForgeryToken] public async Task<IActionResult> Alter([Bind("Id, Name")] StringModel stringModel) { stringModel.ID = 1; return View("~/Pages/Index.cshtml", stringModel); } } }
问题根源分析
Razor Page与MVC控制器模式混用
视图中包含@page指令,说明这是一个Razor Page,而非传统MVC视图。Razor Page采用页面模型(PageModel)驱动逻辑,而你用MVC控制器的动作返回该视图时,系统不会自动初始化对应的PageModel,导致视图中的Model为空,触发空引用异常。模型绑定的大小写不匹配
模型中属性名为ID(大写D),但控制器Bind特性中写的是Id(小写d),虽然你手动设置了stringModel.ID = 1不影响当前功能,但会导致ID属性无法通过模型绑定获取值,属于不规范写法。冗余的
value属性设置
使用asp-for="Name"时,框架会自动从Model或ModelState中填充输入框值,手动添加value="@Model.Name"不仅多余,还可能在ModelState存在时覆盖正确的回显值。
解决方案
方案一:改用纯MVC模式
- 修改视图,移除
@page指令,作为MVC视图使用:
@model SplitString.Models.StringModel <div class="text-left"> <form asp-controller="Home" asp-action="Alter"> <span class="form-control"> <label asp-for="Name">Alter string:</label> <input type="text" asp-for="Name" class="changeString"/> <input class="btn btn-primary" type="submit" value="Update" /> </span> </form> </div>
- 调整控制器
Index动作,首次加载时传入空模型避免空引用:
public IActionResult Index() { return View(new StringModel()); }
- 修正
Bind属性的大小写,与模型属性一致:
[HttpPost] [ValidateAntiForgeryToken] public async Task<IActionResult> Alter([Bind("ID, Name")] StringModel stringModel) { stringModel.ID = 1; return View("Index", stringModel); }
方案二:改用纯Razor Page模式
- 在
Pages/Index.cshtml.cs中创建对应的PageModel:
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.RazorPages; using SplitString.Models; namespace SplitString.Pages { public class IndexModel : PageModel { [BindProperty] public StringModel StringModel { get; set; } public void OnGet() { StringModel ??= new StringModel(); } public IActionResult OnPostAlter() { if (!ModelState.IsValid) { return Page(); } StringModel.ID = 1; return Page(); } } }
- 修改视图,适配Razor Page的表单提交逻辑:
@page @model SplitString.Pages.IndexModel <div class="text-left"> <form method="post" asp-page-handler="Alter"> <span class="form-control"> <label asp-for="StringModel.Name">Alter string:</label> <input type="text" asp-for="StringModel.Name" class="changeString"/> <input class="btn btn-primary" type="submit" value="Update" /> </span> </form> </div>
- 移除原有的
HomeController,Razor Page将独立处理请求。
总结
问题核心是Razor Page与MVC控制器的模式混用,导致视图模型无法正确初始化。选择其中一种模式(纯MVC或纯Razor Page)并保持逻辑一致,即可解决空引用异常和回显失败的问题。同时规范模型绑定的属性大小写,移除冗余的value设置,能让代码更健壮。
内容的提问来源于stack exchange,提问作者Robert Young

