【问题标题】:ASP.NET Core Boolean property binding on form POST does not work as expected表单 POST 上的 ASP.NET Core 布尔属性绑定无法按预期工作
【发布时间】:2018-02-19 15:17:19
【问题描述】:

我已经从 MVC 项目模板生成了一个简单的 ASP.NET Core MVC 应用程序。 HomeController 已被修改以公开两个 Index 方法重载——一个用于 GET,一个用于 POST 请求,两者都使用简单的 BooleanInputsViewModel 呈现相同的 Index.cshtml 视图:

public class BooleanInputsViewModel
{
  public bool IsImportant { get; set; }
  public bool IsActive { get; set; }
  public List<string> Messages { get; } = new List<string>();
}

Index.cshtml 视图如下所示:

@model AspNetCoreBooleanInputs.Models.BooleanInputsViewModel

<h2>
  @nameof(this.Model.IsImportant) = @this.Model.IsImportant.ToString()
  <br />
  @nameof(this.Model.IsActive) = @this.Model.IsActive.ToString()
</h2>

<form class="form-horizontal" method="post">
  <div class="col-md-12">
    <input asp-for="IsImportant" />
    <label asp-for="IsImportant">
    </label>

    <input asp-for="IsActive" />
    <label asp-for="IsActive">
    </label>
  </div>

  <div class="col-md-12">
    <ul>
      @foreach(string message in this.Model.Messages)
      {
        <li>@message</li>
      }
    </ul>
  </div>

  <div class="col-md-12">
    <button type="submit">Submit</button>
  </div>

</form>

最后,HomeControllerIndex 方法是这样实现的:

public IActionResult Index()
{
  var model = new BooleanInputsViewModel();
  model.Messages.Add($"GET values: {nameof(model.IsImportant)} = {model.IsImportant}, {nameof(model.IsActive)} = {model.IsActive}");
  return View(model);
}

[HttpPost]
public IActionResult Index(BooleanInputsViewModel model)
{
  model.Messages.Add($"POST values: {nameof(model.IsImportant)} = {model.IsImportant}, {nameof(model.IsActive)} = {model.IsActive}");

  model.IsActive = !model.IsActive;
  model.IsImportant = !model.IsImportant;

  model.Messages.Add($"Negated POST values: {nameof(model.IsImportant)} = {model.IsImportant}, {nameof(model.IsActive)} = {model.IsActive}");
  return this.View(model);
}

POST 处理程序否定两个模型属性并将修改后的模型传递回视图。但是,否定值不会反映在呈现的表单中,因为它总是呈现最初的 POST 值。对我来说,这看起来像一个错误。我错过了什么明显的东西吗?

完整的 ASP.NET Core 项目发布在这里 - https://github.com/PaloMraz/AspNetCoreBooleanInputs

根据以下@Chris Platt 的回答进行编辑:

嗨,克里斯,感谢您的及时答复。我已经验证使用您建议的 ModelState 字典可以按预期工作,例如:

[HttpPost]
public IActionResult Index(BooleanInputsViewModel model)
{
  model.Messages.Add($"POST values: {nameof(model.IsImportant)} = {model.IsImportant}, {nameof(model.IsActive)} = {model.IsActive}");

  // This does NOT work:
  //model.IsActive = !model.IsActive;
  //model.IsImportant = !model.IsImportant;

  // This works:
  this.ModelState[nameof(model.IsActive)].RawValue = !model.IsActive;
  this.ModelState[nameof(model.IsImportant)].RawValue = !model.IsImportant;

  model.Messages.Add($"Negated POST values: {nameof(model.IsImportant)} = {model.IsImportant}, {nameof(model.IsActive)} = {model.IsActive}");
  return this.View(model);
}

但是,我仍然觉得这是一个非常麻烦的行为,因为一旦调用了 Index 方法,模型就已经被绑定了。为什么在调用View 方法时再次发生绑定,有效地忽略了传入的model 实例?这对我来说看起来不对,抱歉。

另外,你能告诉我你从哪里得到关于ModelState字典组成的信息吗? https://docs.microsoft.com/en-us/aspnet/core/mvc/models/model-binding 的官方文档没有提到 ViewData/ViewBag 作为来源;只有表单值、路由值和查询字符串...

【问题讨论】:

    标签: asp.net-core-mvc model-binding


    【解决方案1】:

    您的表单字段设置为来自 ModelState 的值,该值由来自 RequestViewData/ViewBagfinally Model 的值组成。重要的是,Model 是最后的手段,所以一旦你完成了一个帖子,发布的值(Request)将是该字段设置的值,无论你对Model 进行任何更改。

    我没有尝试在 ASP.NET Core 中执行此操作,但您应该可以改为设置 ModelState["IsActive"].RawValueModelState["IsImportant"].RawValue。假设您可以更改 ModelState 中的值,那么它将在您的视图中显示为您想要的。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-01-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-04-23
      • 1970-01-01
      • 1970-01-01
      • 2018-05-28
      相关资源
      最近更新 更多