ASP.NET Core 3 MVC:对象列表的模型绑定

ASP.NET Core 3 MVC : model binding of a list of objects

我正在尝试 post 一个名字列表到一个表单中,允许用户 select 相关的名字,然后 post 它返回。它变得很好,但 posts 返回空。你能指出我的愚蠢错误吗?

[HttpGet]
public IActionResult Start()
{
    // Get guid and name for all chars and post as list with PC/NPC role and selector.
    // Post this list to the view.
    List<CombatantSelect>cs_list = new List<CombatantSelect>();

    var chars = _context.Characters.AsEnumerable();

    foreach(var c in chars)
    {
        CombatantSelect cs = new CombatantSelect();
        cs.CharGuid = c.Id.ToString();
        cs.Name = c.Name;
        cs.Role = c.PlayerRole.ToString();
        cs_list.Add(cs);
    }

    return View(cs_list);
}

这是post这个列表的控制器动作,见图片。当它到达填充时,我现在它的格式正确。

View of Table

我使用此视图渲染 table。

@using Traveller_Web_2.ViewModels
@model List<CombatantSelect>
@{ 
    ViewData["Title"] = "Start";
    Layout = "~/Views/Shared/_Layout.cshtml";
}

<h1>Start</h1>

<h6>tbc</h6>
<hr />
<div class="row">
    <div class="col-md-4">
        <form method="post" asp-action="Start" asp-controller="Combat">
            <table class="table">
                <thead class="">
                    <tr>
                        <th>Select for combat</th>
                        <th>Name</th>
                        <th>Role</th>
                    </tr>
                </thead>
                <tbody>

                        @Html.EditorForModel("CombatantSelect")
                </tbody>
            </table>
                <input asp-action="Start" asp-controller="Combat" type="submit" value="Select" class="btn btn-primary" />
        </form>
    </div>
</div>

这是视图模型:

public class CombatantSelect
{
        [Key]
        public string CharGuid { get; set; }
        public string Name { get; set; }
        public string Role { get; set; }
        public bool SelectForCombat { get; set; }
}

而这个编辑器模板:

@model IEnumerable<Traveller_Web_2.ViewModels.CombatantSelect>
@for (int i = 0; i < Model.Count(); i++)
{
    <tr>
        <td>
            <input id="SelectForCombat[@i]" asp-for="@Model.ElementAt(i).SelectForCombat" type="checkbox" name="SelectForCombat[@i]" itemid="@i" />
           </td>
        <td>
           <input id="Name[@i]" name="Name[@i]" asp-for="@Model.ElementAt(i).Name" type="text"  />
        </td>
        <td>
            <input id="Name[@i]" name="Name[@i]" asp-for="@Model.ElementAt(i).Role" type="text"  />
            <input id="CharGuid[@i]" name="CharGuid[@i]" type="hidden" asp-for="@Model.ElementAt(i).CharGuid"  />
        </td>
    </tr>
}

这是它呈现的部分内容,用于演示 ID 和名称中的索引;

<form method="post" action="/Combat/Start">
            <table class="table">
                <thead class="">
                    <tr>
                        <th>Select for combat</th>
                        <th>Name</th>
                        <th>Role</th>
                    </tr>
                </thead>
                <tbody>

                            <tr>
        <td>
            <input id="SelectForCombat[0]" type="checkbox" name="SelectForCombat[0]" itemid="0" data-val="true" data-val-required="The SelectForCombat field is required." value="true" />
           </td>
        <td>
           <input id="Name[0]" name="Name[0]" type="text" value="Chief Sales Officer" />
        </td>
        <td>
            <input id="Name[0]" name="Name[0]" type="text" value="Player" />
            <input id="CharGuid[0]" name="CharGuid[0]" type="hidden" value="bf373774-691a-43f2-5ff8-08d75cab14e2" />
        </td>
    </tr>
    <tr>
        <td>
            <input id="SelectForCombat[1]" type="checkbox" name="SelectForCombat[1]" itemid="1" value="true" />
           </td>
        <td>
           <input id="Name[1]" name="Name[1]" type="text" value="Deputy Shop Assistant" />
        </td>
        <td>
            <input id="Name[1]" name="Name[1]" type="text" value="FriendlyNPC" />
            <input id="CharGuid[1]" name="CharGuid[1]" type="hidden" value="347298c5-984b-460a-f9f8-08d75cac89b9" />
        </td>
    </tr>

它post回到控制器中的这个方法;

[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Start([Bind("CharGuid, Role, SelectForCombat, Name")] 
                           List<CombatantSelect> combatantSelects)
{
    // If it works do something with it, if not give it back
    if (ModelState.IsValid)
    {
        combatantSelects.Count();
    }

    return View(combatantSelects);
}

ModelState 没有错误 - 它告诉我有一个列表 CombatantSelect 但它的计数为 0.

有什么想法吗?非常感谢。

MVC 从发布的值重新创建模型。它检查特定名称以再次重新创建模型。因此 HTML 中的名称应与模型中的名称对齐。尝试下面的代码来解决模型绑定问题

List<Traveller_Web_2.ViewModels.CombatantSelect> 类型的模型传递给视图

如下修改代码,以便生成 HTML 个与模型对齐的输入控件名称

@model List<Traveller_Web_2.ViewModels.CombatantSelect>
@for (int i = 0; i < Model.Count; i++)
{
    <tr>
        <td>
            @Html.CheckBoxFor(x => x[i].SelectForCombat)
        </td>
        <td>
           @Html.TextBoxFor(x => x[i].Name)
        </td>
        <td>
           @Html.TextBoxFor(x => x[i].Role)
           @Html.HiddenFor(x => x[i].CharGuid)
        </td>
    </tr>
}

以上代码应创建名称与模型一致的输入。

开发到对象表单列表的下一个示例后,我成功地使用助手标签而不是 Html 助手绑定了模型。

                @for (int i = 0; i < Model.returnCount(); i++)
                {
                <tr>
                    <td class="col-md-2">
                        <input asp-for="Combatants[i].CharacterName" type="text" />
                        <input asp-for="Combatants[i].CharacterGuid" type="hidden" />
                    </td>
                    <td class="col-md-2">
                        <input asp-for="Combatants[i].CharRoll" type="text" />
                    </td>
                    <td class="col-md-1">
                        <input asp-for="Combatants[i].IntModFromStats" type="number" />
                    </td>
                    <td class="col-md-1">
                        <input asp-for="Combatants[i].DiceRoll" type="number" />
                    </td>
                    <td class="col-md-2">
                        <select asp-for="Combatants[i].Ambush" asp-items="Html.GetEnumSelectList<AmbushMod>()">
                        </select>
                    </td>
                    <td class="col-md-1">
                        <input asp-for="Combatants[i].OtherMods" type="number" />
                    </td>
                </tr>
                }

并且允许指定输入类型、下拉框等