プログラムを中心とした個人的なメモ用のブログです。 タイトルは迷走中。
内容の保証はできませんのであしからずご了承ください。

2019/04/24

[ASP.NET Core] Post メソッドで配列やリストを渡す

event_note2019/04/24 0:12

ASP.NET Core で、View から Controller に Post メソッドでデータを渡す際、配列やリストはどう渡せばいいか試してみました。

環境

  • Visual Studio 2017
  • ASP.NET Core 2.2

プリミティブ型の場合

Controller で以下のような値を受け取りたいとします。

[HttpPost]
public IActionResult PostTest2(string[] names)
{
    // Do something
    
    return View();
}

View は以下のようになります。

<form asp-controller="Home" asp-action="PostTest">
    <table class="table">
        <thead>
            <tr>
                <th>Name</th>
            </tr>
        </thead>
        <tbody>
            @for (var i = 0; i < 5; i++)
            {
                <tr>
                    <td><input type="text" class="form-control" name="names"></td>
                </tr>
            }
        </tbody>
    </table>
    <input type="submit" class="btn btn-primary" />
</form>

name に引数名を指定することで、配列やリストに順に格納されて渡されます。

複合型の場合

クラスなどの場合、上記のように渡すことはできませんでした。

例として、View から Controller へ、以下のようなモデルを渡してみます。

public class SampleViewModel
{
    public List<Person> Persons { get; set; }
}

public class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
}

Controller は以下のような感じで普通に受け取ります。

public class HomeController : Controller
{
    [HttpPost]
    public IActionResult PostTest(SampleViewModel vm)
    {
        return View(vm);
    }
}

肝心の View ですが、以下のようになります。

@model SampleViewModel

<form asp-controller="Home" asp-action="PostTest">
    <table class="table">
        <thead>
            <tr>
                <th>Name</th>
                <th>Age</th>
            </tr>
        </thead>
        <tbody>
            @for (var i = 0; i < 5; i++)
            {
                <tr>
                    <td><input type="text" class="form-control" asp-for="@Model.Persons[i].Name"></td>
                    <td><input type="text" class="form-control" asp-for="@Model.Persons[i].Age"></td>
                </tr>
            }
        </tbody>
    </table>
    <input type="submit" class="btn btn-primary" />
</form>

大事なのは、asp-for="@Model.Persons[i].Name" の部分でしょうか。
いろいろ試してみたのですが、どうやらインデックスまで指定して渡す必要があるようです。

今回 PersonsList として定義していますが、IEnuemrable では渡せませんでした。
配列や IReadOnlyList などは OK でした。
もしインデックスを指定せずにできるやり方があるならば教えていただきたいです。

尚、上記は for で 5 回まわしているので、Contoller 側で受け取った時には要素数が 5 で固定になります。

サンプルとしては以上ですが、入力欄が動的に変わったりする場合などはインデックスを調整するなど一工夫する必要がありそうです。