ASP.NET MVC POST提交后部分模型字段为null问题排查
问题根因
模型绑定后部分字段为null的核心原因是:ASP.NET Core 默认模型绑定器仅能对声明了public set访问器的属性赋值。
查看ImportSheepViewModel定义,以下字段的set访问器被设置为private,模型绑定阶段无法对这些属性写入值,即使请求Payload中已经携带了对应字段的提交数据,绑定完成后这些字段仍会保持类型默认值(引用类型默认值为null,bool类型默认值为false):
HasErrorBoxIdFatherIdMotherIdRaceId
额外存在一个视图渲染问题:表头定义的第三列为Race、第四列为Gender,但tbody单元格实际渲染时第三列输出的是Gender、第四列输出的是Race,会导致页面展示内容与表头不匹配,该问题不会影响模型绑定结果,但建议调整顺序保持一致。

修复方案
将上述几个属性的private set修改为public set即可,修改后的ViewModel核心代码如下:
public class ImportSheepViewModel { public ImportSheepViewModel() { HasError = false; } public string Code { get; set; } public DateTime BirthDate { get; set; } public string Race { get; set; } public string Gender { get; set; } public string Father { get; set; } public string Mother { get; set; } public string BoxDescription { get; set; } // 调整set访问器为public public bool HasError { get; set; } public string BoxId { get; set; } public string FatherId { get; set; } public string MotherId { get; set; } public string RaceId { get; set; } public Gender FinalGender { get; set; } public void Validate() { if (string.IsNullOrEmpty(Code) || string.IsNullOrEmpty(Race) || string.IsNullOrEmpty(Gender) || string.IsNullOrEmpty(BoxDescription)) HasError = true; var gender = Gender.ToLower(); if (gender != "male") { if (gender != "female") HasError = true; } } public void SetBoxId(string boxId) { BoxId = boxId; } public void SetFatherId(string fatherId) { if (string.IsNullOrEmpty(fatherId)) FatherId = null; FatherId = fatherId; } public void SetMotherId(string motherId) { if (string.IsNullOrEmpty(motherId)) MotherId = null; MotherId = motherId; } public void SetRaceId(string raceId) { RaceId = raceId; } public void SetError() { HasError = true; } }
如果有特殊需求必须保留private set访问器,可以通过自定义模型绑定器实现非公共属性的赋值,但常规业务场景下直接使用public set是最符合框架约定、维护成本最低的方案。
调整后视图代码参考
@model List<ImportSheepViewModel> <div class="row"> <div class="col-12"> <form method="post" asp-action="PostSheep" asp-controller="Sheep"> <table class="table table-responsive"> <thead> <tr> <th>Code</th> <th>BirthDate</th> <th>Race</th> <th>Gender</th> <th>Father</th> <th>Mother</th> <th>BoxDescription</th> </tr> </thead> <tbody> @for (var i = 0; i < Model.Count; i++) { if (Model[i].HasError) { <tr class="alert alert-danger"> <td> @Model[i].Code <input type="hidden" asp-for="@Model[i].Code"/> </td> <td> @Model[i].BirthDate <input type="hidden" asp-for="@Model[i].BirthDate"/> </td> <td> @Model[i].Race <input type="hidden" asp-for="@Model[i].RaceId"/> <input type="hidden" asp-for="@Model[i].Race"/> </td> <td> @Model[i].Gender <input type="hidden" asp-for="@Model[i].Gender"/> </td> <td> @Model[i].Father <input type="hidden" asp-for="@Model[i].FatherId"/> <input type="hidden" asp-for="@Model[i].Father"/> </td> <td> @Model[i].Mother <input type="hidden" asp-for="@Model[i].MotherId"/> <input type="hidden" asp-for="@Model[i].Mother"/> </td> <td> @Model[i].BoxDescription <input type="hidden" asp-for="@Model[i].BoxId"/> <input type="hidden" asp-for="@Model[i].BoxDescription"/> <input type="hidden" asp-for="@Model[i].HasError"/> </td> </tr> } else { <tr class="alert alert-success"> <td> @Model[i].Code <input type="hidden" asp-for="@Model[i].Code"/> </td> <td> @Model[i].BirthDate <input type="hidden" asp-for="@Model[i].BirthDate"/> </td> <td> @Model[i].Race <input type="hidden" asp-for="@Model[i].RaceId"/> <input type="hidden" asp-for="@Model[i].Race"/> </td> <td> @Model[i].Gender <input type="hidden" asp-for="@Model[i].Gender"/> </td> <td> @Model[i].Father <input type="hidden" asp-for="@Model[i].FatherId"/> <input type="hidden" asp-for="@Model[i].Father"/> </td> <td> @Model[i].Mother <input type="hidden" asp-for="@Model[i].MotherId"/> <input type="hidden" asp-for="@Model[i].Mother"/> </td> <td> @Model[i].BoxDescription <input type="hidden" asp-for="@Model[i].BoxId"/> <input type="hidden" asp-for="@Model[i].BoxDescription"/> <input type="hidden" asp-for="@Model[i].HasError"/> </td> </tr> } } </tbody> </table> <div class="form-group"> <input type="submit" value="Import Data" class="btn btn-success"/> </div> </form> </div> </div>
内容的提问来源于stack exchange,提问作者Danijel Boksan
相关产品推荐
相关产品推荐

