しばやん雑記

Azure とメイドさんが大好きなフリーランスのプログラマーのブログ

ASP.NET MVC のモデルバインダで Dictionary を扱う

ASP.NET MVC のモデルバインダは List や配列は添え字がシーケンシャルであれば、複合型でも問題なくバインド出来るのは知っていましたが、今日まで Dictionary のバインドに対応してることを知りませんでした…。これは恥ずかしい。

ASP.NET Wire Format for Model Binding to Arrays, Lists, Collections, Dictionaries - Scott Hanselman

Scott Hanselman 氏のブログに記述がありますが、日付は何と驚きの 2009 年ですよ!

という訳で、ASP.NET MVC では Dictionary のバインドは出来ますが、記法がかなり特殊になっています。現在主流の Expression を使った HTML ヘルパーはこの書き方に対応していないので、殆どの人は知らずに生きている気はしますね…。

ミニマムなサンプルコードを用意したので読んでもらった方が理解できる気がします。

public class HomeController : Controller
{
    public ActionResult Index()
    {
        var model = new Dictionary<int, string>
        {
            { 1, "foo" },
            { 10, "bar" },
            { 100, "baz" }
        };

        return View(model);
    }

    [HttpPost]
    public ActionResult Index(Dictionary<int, string> model)
    {
        return View(model);
    }
}

アクションは Dictionary を作って受け取っているだけなので、違和感は全くないですね。

しかしながら、ビューはというと。

@model IDictionary<int, string>

@using (Html.BeginForm())
{
    var i = 0;
    foreach (var item in Model)
    {
        <input type="hidden" name="[@i].Key" value="@item.Key" />
        <input type="text" name="[@i].Value" value="@item.Value" />
        i += 1;
    }

    <input type="submit" />
}

foreach を使っているのに添え字のためにカウンタ変数を用意していたり、Key と Value プロパティという存在しないものを触っていたりで、知らなければかけないコードになってます。

凄く見た目が気持ち悪いコードですが、動かすとちゃんとバインドされます。なんだか不思議な気分です。

f:id:shiba-yan:20130314235117p:plain

普段使いするような書き方ではないと思いますが、どうしても非シーケンシャルなキーを持つデータをフォームで扱いたい場合には有効ですね。