POST 上的 SelectList 始终为 null 导致模型状态无效

SelectList always null on POST causes Model State to be Invalid

我知道 SelectListItems 的目的是不 return 支持 post 上的项目并且可能为空,但正因为如此,我的 ModelState.IsValid 条件始终为假,研究包含列表的字段是具有无效属性的字段。我尝试了不同的方法并坚持解决这个问题

查看

 <label asp-for="Studies" class="form-label"></label>
 <select asp-for="SelectedStudyGuid" asp-items="@Model.Studies" class="form-control" autocomplete="off">
   <option value="">Select Study</option>
 </select>
 <span asp-validation-for="SelectedStudyGuid" class="text-danger"></span>

ViewModel

public class AddStudyViewModel
{
    public string ParticipantGuid { get; set; }

    public IEnumerable<SelectListItem> Studies { get; set; }
    public string SelectedStudyGuid { get; set; }
    
    [DataType(DataType.Date)]
    public DateTime? StartDate { get; set; }
    
    [DataType(DataType.Date)]
    public DateTime? EndDate { get; set; }
}

控制器

  private List<SelectListItem> GetStudyCatalog()
    {
        return _repo.GetStudyCatalog().Select(s => new SelectListItem
        {
            Text = s.Name,
            Value = s.Guid
        }).ToList();
    }

    [HttpGet]
    public IActionResult AddStudy(string participantGuid)
    {
        var model = new AddStudyViewModel
        {
            Studies = GetStudyCatalog(),
            ParticipantGuid = participantGuid
        };
        
        return PartialView("_AddStudyModal", model);
    }

    [HttpPost]
    public IActionResult AddStudy(AddStudyViewModel model)
    {
        if (ModelState.IsValid)
        {
           var response= _repo.AddStudy(model.SelectedStudyGuid, model.ParticipantGuid, model.StartDate, model.EndDate);
           
            if (response.Success)
            {
                TempData["Message"] = response.Message;
                return RedirectToAction("EditParticipant", new {id = response.NewGuid});
            }
        }

        model.Studies = GetStudyCatalog();
        return PartialView("_AddStudyModal", model);
    }

问题出在您单击按钮将表单数据提交回控制器时。

此时客户端代码发送表单上存在的输入字段,而您没有包含 SelectListItem 的输入字段。 SelectedStudyGuid select 列表是针对该领域的,而不是针对整个研究。

在 post 操作中接收到的 AddStudyViewModel 实例使用客户端发送的数据在服务器端重建,因此研究 属性.

通常 post 操作不需要 SelectListItem 数据,只有在 get 操作中才需要,您可以使用一些临时存储(如 ViewBag

)简单地传递它

所以你可以用

修复

型号

public class AddStudyViewModel
{
    public string ParticipantGuid { get; set; }

    public string SelectedStudyGuid { get; set; }
    
    [DataType(DataType.Date)]
    public DateTime? StartDate { get; set; }
    
    [DataType(DataType.Date)]
    public DateTime? EndDate { get; set; }
}

控制器

[HttpGet]
public IActionResult AddStudy(string participantGuid)
{
    var model = new AddStudyViewModel
    {
        ParticipantGuid = participantGuid
    };
    ViewBag.Studies = GetStudyCatalog(),
    return PartialView("_AddStudyModal", model);
}

VIEW

 <label asp-for="Studies" class="form-label"></label>
 <select asp-for="SelectedStudyGuid" asp-items="@ViewBag.Studies" class="form-control" autocomplete="off">
   <option value="">Select Study</option>
 </select>
 <span asp-validation-for="SelectedStudyGuid" class="text-danger"></span>

只有在使用 net 6 时才会发生这种情况。要修复它,只需将 Studies 设置为 nullable

public List<SelectListItem>? Studies { get; set; }

或者聪明的开发人员在做什么,他们只是从项目中删除可为空值

 <TargetFramework>net6.0</TargetFramework>
    <!--<Nullable>enable</Nullable>-->

用 ViewBag 代替 ViewModel 很不专业