Posting Data To a List in ASP.Net MVC – Part 1

Recently I came across several stackoverflow questions that asked about binding data to lists, and after writing lengthy answers to these questions I thought I should write a blog post about it so that I can refer people without spending lot of time writing individual answers. So here we go. For this post, I will be using a sample application to explain things. It will have a ViewModel called UserInfo. To keep things simple, we’ll have the following properties in the model.

Posting Primitive Type Properties
 public class UserInfo
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public int Age { get; set; }

    public string HouseNo { get; set; }
    public string Address1 { get; set; }
    public string Address2 { get; set; }
    public string City { get; set; }
    public string PostCode { get; set; }
}

This is what the Html code looks like for the above view model.

@using (Html.BeginForm())
{
    @Html.ValidationSummary(true)
    <fieldset>
        <legend>UserInfo</legend>

        <div class="editor-label">
            @Html.LabelFor(model => model.FirstName)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.FirstName)
            @Html.ValidationMessageFor(model => model.FirstName)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.LastName)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.LastName)
            @Html.ValidationMessageFor(model => model.LastName)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.Age)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.Age)
            @Html.ValidationMessageFor(model => model.Age)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.HouseNo)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.HouseNo)
            @Html.ValidationMessageFor(model => model.HouseNo)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.Address1)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.Address1)
            @Html.ValidationMessageFor(model => model.Address1)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.Address2)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.Address2)
            @Html.ValidationMessageFor(model => model.Address2)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.City)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.City)
            @Html.ValidationMessageFor(model => model.City)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.PostCode)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.PostCode)
            @Html.ValidationMessageFor(model => model.PostCode)
        </div>
</fieldset>
}

In MVC, posting primitive data to your action is fairly straightforward. You use @using(Html.BeginForm()){} and have your input fields within the curly braces and have a submit button as above to post your data to the action and the DefaultModelBinder will take care of the binding. using fiddler, We’ll inspect the posted data when the user submit the form.

FirstName=Amila&LastName=ABC&Age=20&HouseNo=1+abc&Address1=my+street&Address2=&City=My+City&PostCode=

below is the watch window screenshot of the above posted data

Data binded by the default model binder

But what if you want to submit data to a Collection? will it work the same way? It will, but only if the collection is a collection of primitive type. We’ll modify the view model a bit so that it has a list of string which take user’s favourite song names.

Posting Primitive Type Properties, including primitive type collection
 public class UserInfo
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public int Age { get; set; }

    public string HouseNo { get; set; }
    public string Address1 { get; set; }
    public string Address2 { get; set; }
    public string City { get; set; }
    public string PostCode { get; set; }

    public List FavouriteSongs { get; set; }
}

For a start, we’ll let the user add just 5 of their favourite songs by having 5 text boxes. There are few ways to do this, but there’s one caveat. I do not recommend the first method I’m going to show you here. It will work for the first submit, but if your ModelState.IsValid is false (i.e. your front end validation didn’t work for some reason), then when it returns to the view with the ModelState it wouldn’t populate the texboxes that belong to the list correctly. Below is the View code that is added to take data for the list.

@*collection of a primitive type, method 1*@
<div class="editor-label">
    @Html.LabelFor(model => model.FavouriteSongs)
</div>
<div class="editor-field">
    @Html.TextBoxFor(model => model.FavouriteSongs)<br/>
    @Html.TextBoxFor(model => model.FavouriteSongs)<br/>
    @Html.TextBoxFor(model => model.FavouriteSongs)<br/>
    @Html.TextBoxFor(model => model.FavouriteSongs)<br/>
    @Html.TextBoxFor(model => model.FavouriteSongs)<br/>
</div>

 

FirstName=Amila&LastName=ABC&Age=12&HouseNo=4&Address1=123&Address2=456&City=London&PostCode=123456&FavouriteSongs=song1&FavouriteSongs=Song2&FavouriteSongs=song3&FavouriteSongs=song4&FavouriteSongs=song5

If we take a look at the binded data, we can see that FavouriteSongs List has been instantiated with the values as they appear in the request body (i.e. first FavouriteSongs parameter in the request body is assigned to index 0 in the list and so on).

List of Primitive Type

As I mentioned before, it works. But if front end validation did not work as expected and the server validation fails we will have to return our model to the view again. At this point it will not populate the textboxes properly as we are using @Html.TextBoxFor(model => model.FavouriteSongs) . As you can see we are not specifying any index in there and it will assign value  “song1” which is the value at index 0 to all the textboxes. We can make one simple code change to make this work by adding index to individual textbox for the FavouriteSongs list.

@*collection of a primitive type, method 2*@
<div>
    @Html.LabelFor(model => model.FavouriteSongs)
</div>
<div>
    @Html.TextBoxFor(model => model.FavouriteSongs[0])<br/>
    @Html.TextBoxFor(model => model.FavouriteSongs[1])<br/>
    @Html.TextBoxFor(model => model.FavouriteSongs[2])<br/>
    @Html.TextBoxFor(model => model.FavouriteSongs[3])<br/>
    @Html.TextBoxFor(model => model.FavouriteSongs[4])<br/>
</div>

Now the request body looks as follows (Note: %5B is encoded [ and %5D is html encoded ])

FirstName=Amila&LastName=ABC&Age=0&HouseNo=4&Address1=Street&Address2=&City=MyCity&PostCode=12345&FavouriteSongs%5B0%5D=song1&FavouriteSongs%5B1%5D=song2&FavouriteSongs%5B2%5D=song3&FavouriteSongs%5B3%5D=song4&FavouriteSongs%5B4%5D=song5

Above, I’ve explained how you can post a collection of a certain primitive type to the server. I will put together part 2 of this post which will relate to advance usage of Collections in a view such as adding/removing items to/from DOM where it removes the item from the list properly and of course using collection of a certain complex object.

One thought on “Posting Data To a List in ASP.Net MVC – Part 1

  1. Timelog 16/04/2014 at 10:43 am Reply

    This is a very useful post, thanks a lot 🙂 When can we expect part two? As that would be very helpful for my current project.

Leave a comment