[I solved this myself, see my answer for cause]
I'm having trouble getting form values for a IList<> argument in a controller method set properly.
My controller class looks like this:
public class ShoppingBasketController : Controller { public ActionResult Index() { return View(); } [AcceptVerbs(HttpVerbs.Post)] public ActionResult Add(IList<ShoppingBasketItem> items) { Session["basket"] = items; // for testing return RedirectToAction("Index"); } } public class ShoppingBasketItem { public int ItemID; public int ItemQuantity; }
The slightly trimmed form:
<% using (Html.BeginForm("Add", "ShoppingBasket")) { %> <% int codeIndex = 0; foreach (Product product in products) { %> <%= Html.Hidden("items[" + codeIndex + "].ItemID", product.Id) %> <%= Html.TextBox("items[" + codeIndex + "].ItemQuantity", "0", new { size = "2"}) %> <% codeIndex++; } } %>
Which produces markup like:
<form action="/Basket/Add" method="post"> <input id="items[0]_ItemID" name="items[0].ItemID" type="hidden" value="1" /> <input id="items[0]_ItemQuantity" name="items[0].ItemQuantity" size="2" type="text" value="0" /> <input id="items[1]_ItemID" name="items[1].ItemID" type="hidden" value="2" /> <input id="items[1]_ItemQuantity" name="items[2].ItemQuantity" size="2" type="text" value="0" /> <input id="items[2]_ItemID" name="items[2].ItemID" type="hidden" value="3" /> <input id="items[2]_ItemQuantity" name="items[2].ItemQuantity" size="2" type="text" value="0" /> </form>
I've checked the form values that get submitted and they are correct. The correct number of ShoppingBasketItem
s also get put into Session["basket"
], however both the ItemID
and ItemQuantity
of each are zero. It appears to be correctly decoding the list of form values, but not picking up the properties themselves.
I'm using MVC RC2, and based on an article by Scott Hanselman I'm pretty sure my code is correct. Am I missing something?
What Is Model Binding? ASP.NET MVC model binding allows mapping HTTP request data with a model. It is the procedure of creating . NET objects using the data sent by the browser in an HTTP request. Model binding is a well-designed bridge between the HTTP request and the C# action methods.
Using the Razor syntax instead of plain HTML it is very easy to construct and bind your form elements to the corresponding data. In this case the label will show the value of the Display attribute in the User class and the values of the user will be filled in the textboxes.
MVC doesn't use data bindings like old web api. You have to use model bindings in a MVC or MVVM approach.
Solution
After downloading the MVC source I still couldn't see why it wouldn't work, so I presumed it must be something to do with the type I was attempting to bind. Sure enough, the values being member variables, as opposed to properties, was the culprit. This is because the model binder uses reflection to set properties, which it wasn't finding through the call to TypeDescriptor.GetProperties(Type)
.
Updating the value class to this solved it (after hours of hitting head off wall I should add!!):
public class ShoppingBasketItem { public int ItemID { get; set; } public int ItemQuantity { get; set; } }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With