1

I have an MVC4 web app.

My model contains a Dictionary whose values are an array of one of my own classes.

Given the view below, I'm expecting the default model binder to be able to reconstruct the model/dictionary when I submit to the Post action, however this is not the case.

I do get a MyModel instance and ModelState.IsValid == true, however the dictionary has no key/value pairs in it.

Am I missing something (not adhering to the prescribed convention?) or is this a scenario that requires a custom model binder/digging into the Request.Form collection?

Sample code to reproduce this behaviour:

Model:

public class MyClass
{
    public int MyInt { get; set; }

    public string MyString { get; set; }
}

public class MyModel
{
    public Dictionary<int, MyClass[]> MyDictionary { get; set; }
}

View:

@using (Html.BeginForm("MyAction", "Home", FormMethod.Post))
{
    foreach (var key in Model.MyDictionary.Keys)
    {
        <hr />@key<br />
        for (int i = 0; i < Model.MyDictionary[key].Length; i++)
        {
            @Html.HiddenFor(m => m.MyDictionary[key][i].MyInt);
            @Model.MyDictionary[key][i].MyInt
            @Html.TextBoxFor(m => m.MyDictionary[key][i].MyString);<br/>
        }
    }
    <hr />
    <button type="submit">Post</button>
}

Controller:

[HttpGet]
public ActionResult MyAction()
{
    var model = new MyModel()
    {
        MyDictionary = new Dictionary<int, MyClass[]> {
            {10, new MyClass[] { new MyClass  { MyInt = 1, MyString = "Foo" }, new MyClass { MyInt = 2, MyString = "Bar"}}},
            {20, new MyClass[] { new MyClass  { MyInt = 3, MyString = "Fubar" }}}
        }
    };
    return View(model);
}

[HttpPost]
public ActionResult MyAction(MyModel model)
{
    return View(model);
}
Murali Murugesan
  • 22,423
  • 17
  • 73
  • 120
Veli Gebrev
  • 2,481
  • 4
  • 31
  • 48
  • Try changing the `foreach` loop to a `for` loop. There are some issues in MVC4 that the `EditorView` with `foreach` loops dont bind to the correct model name. – devqon May 28 '14 at 09:13
  • Thanks for the suggestion, I tried that, and the exact same html is sent to the browser and form data sent back to the server, regardless of which type of loop I used. Same result. I'm endeavouring to write a custom ModelBinder, will share it as a solution if none other comes up. – Veli Gebrev May 28 '14 at 09:26
  • Can you add the post data sent to server? Use firebug/chrome console and monitor the request post data – Murali Murugesan May 28 '14 at 09:26
  • This is the request body: `MyDictionary%5B10%5D%5B0%5D.MyInt=1&MyDictionary%5B10%5D%5B0%5D.MyString=Foo&MyDictionary%5B10%5D%5B1%5D.MyInt=2&MyDictionary%5B10%5D%5B1%5D.MyString=Bar&MyDictionary%5B20%5D%5B0%5D.MyInt=3&MyDictionary%5B20%5D%5B0%5D.MyString=Fubar` – Veli Gebrev May 28 '14 at 09:32
  • 1
    Your key is missing. I think you should render the key of the dictionary in a hidden field too – qamar May 28 '14 at 09:42

1 Answers1

2

You need to understand how default model binder from the Hanselman's post.

http://www.hanselman.com/blog/ASPNETWireFormatForModelBindingToArraysListsCollectionsDictionaries.aspx

Here in your case you have taken different controls for key and values and your model binder will not understand what's going on.

Take a look on similar question from the following link. ASP.NET MVC Binding to a dictionary

Community
  • 1
  • 1
Jalpesh Vadgama
  • 13,653
  • 19
  • 72
  • 94