J86
J86

Reputation: 15237

Collection is readonly on array in ViewModel

I have an MVC ViewModel that looks like this:

public class FruitBoxViewModel {

    public FruitBoxViewModel()
    {
        BoxLabels = new BoxLabelViewModel[3];
    }

    public int Id { get; set; }
    public string Name { get; set; }
    public BoxLabelViewModel[] BoxLabels {get; set; }
}

A commented requested to see what the BoxLabelViewModel looks like, here it is:

public class BoxLabelViewModel {
    public string SkuCode {get; set;}
    public int? ProductionNumber { get; set; }
}

Each FruitBox can have between 1 and 3 BoxLabels, no more, no less. To enforce, this, I thought I'd use an Array instead of a List.

I have a for loop in my Razor view that handles my inputs on the page:

@for(var i = 0; i < 3; i++ )
{
  @Html.LabelFor(model => Model.BoxLabels[i].SkuCode)
  @Html.EditorFor(m => Model.BoxLabels[i].SkuCode, new { htmlAttributes = new { @class = "form-control" } })
}

When I submit the form, I get the yellow screen of death (YSOD) with the error:

Collection is read-only.

Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details: System.NotSupportedException: Collection is read-only.

Is there a rule I don't know about that says you should never use an Array in your ViewModels or something?

Upvotes: 4

Views: 1206

Answers (1)

Rafal
Rafal

Reputation: 12619

This is one of the 'got you' cases of using array instead of list. Model binder will not create new instance of an array because you have provided one in constructor. Then it will use it as IList instance and try to invoke Insert or Add and such calls will fail for array and succeed for list.

Just remove the assignment form constructor or use list in your model and write some JS to validate your form before sending post request. Then validate count of items on server side.

Upvotes: 5

Related Questions