Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Model binding to Lists throws "Collection is read-only" exception

I have a class like this:

public class SomeModel
{
    public List<Item> Items { get; set; }

    public SomeModel()
    {
        this.Items = new List<Item>();
    }

}

Where there can be a variable amount of Items upon form post, zero to many. I'm using javascript to dynamically append hidden input fields on submit:

$("#container").children(".item").each(function (i) {
    form.append('<input type="hidden" name="Items[' + i + '].Id" value="' + $(this).val() + '" />');
});

However, after submitting, I get this error:

System.NotSupportedException: Collection is read-only.

The rendered syntax is basically the same as one I would get using @Html.HiddenFor(model => model.Items[i].Id) with model.Items being an array instead of a list, and that works fine. What is going wrong here?

Action Method signature:

public ActionResult Post(SomeModel m)
{
like image 623
idlackage Avatar asked Dec 05 '13 16:12

idlackage


3 Answers

Your Array was probably working on Insert (Where a new object is created).

The issue happens when you try to update your model.

For me, replacing string[] to List<string> solved the problem.

//instead of....
public string[] TagsArray { get; set; }

//I now have
public List<string> TagsArray { get; set; }
like image 173
ThiagoPXP Avatar answered Nov 16 '22 11:11

ThiagoPXP


I'm not sure why the array worked before, but apparently, that was what was causing the problem--not the Lists. When I changed that array to a List, I no longer got the error. Should've mentioned that I still had the array in my model, sorry.

like image 42
idlackage Avatar answered Nov 16 '22 10:11

idlackage


MVC Model Binder should work with arrays, so replacing with a List is a workaround, but not the right solution.

I had the same problem, but it happens to me only sometimes. So I did not understand why this issue takes place. Then I discovered something that I think is worhty to share: the problem was in the javascript code.

Here my scenario:

I have a model where I use one array

public class SomeModel
{
    public Item[] Items { get; set; }

    public SomeModel()
    {
        this.Items = new Item[3] {0, 0, 0};
    }
}

I found the solution just changing the javascript that I use to call the web method!

-> case A - It throws the exception "Collection is read only"

$.ajax({
        type: "POST",
        async: true,
        url: myUrl,
        data: JSON.stringify(myData),
        contentType: "application/json; charset=utf-8",
        dataType: "html"
    })

-> case B - It works without any exception!

$.ajax({
        type: "POST",
        async: true,
        url: myUrl,
        data: myData,
        dataType: "html"
    })

Actually MVC model binding should works with array, so replacing with a List was not the answer I was looking for.

Good coding.

like image 1
Lorenzo Avatar answered Nov 16 '22 10:11

Lorenzo