Model Binding To A List

aspnetmvc 0 comments suggest edit

Download the sample project to play with the code as you read this blog post.

Using the DefaultModelBinder in ASP.NET MVC, you can bind submitted form values to arguments of an action method. But what if that argument is a collection? Can you bind a posted form to an ICollection<T>?

Sure thing! It’s really easy if you’re posting a bunch of primitive types. For example, suppose you have the following action method.

public ActionResult UpdateInts(ICollection<int> ints) {

  return View(ints);
}

You can bind to that by simply submitting a bunch of form fields each having the same name. For example, here’s an example of a form that would bind to this, assuming you keep each value a proper integer.

<form method="post" action="/Home/UpdateInts">
    <input type="text" name="ints" value="1" />
    <input type="text" name="ints" value="4" />
    <input type="text" name="ints" value="2" />
    <input type="text" name="ints" value="8" />
    <input type="submit" />
</form>

If you were to take fiddler and look at what data actually gets posted when clicking the submit button, you’d see the following.

ints=1&ints=4&ints=2&ints=8

The default model binder sees all these name/value pairs with the same name and converts that to a collection with the key ints, which is then matched up with the ints parameter to your action method. Pretty simple!

Where it gets trickier is when you want to post a list of complex types. Suppose you have the following class and action method.

public class Book {
    public string Title { get; set; }
    public string Author { get; set; }
    public DateTime DatePublished { get; set; }
}

//Action method on HomeController
public ActionResult UpdateProducts(ICollection<Book> books) {
    return View(books);
}

You might think we could simply post the following to that action method:

Title=title+one&Author=author+one&DateTime=1/23/1975 &Title=author+two&Author=author+two&DateTime=6/6/2007…

Notice how we simply repeat each property of the book in the form post data? Unfortunately, that wouldn’t be a very robust approach. One reason is that we can’t distinguish from the fact that there may well be another Title input unrelated to our list of books which could throw off our binding.

Another reason is that the checkbox input does not submit a value if it isn’t checked. Most input fields, when left blank, will submit the field name with a blank value. With a checkbox, neither the name nor value is submitted if it’s unchecked! This again can throw off the ability of the model binder to match up submitted form values to the correct object in the list.

To bind complex objects, we need to provide an index for each item, rather than relying on the order of items. This ensures we can unambiguously match up the submitted properties with the correct object.

Here’s an example of a form that submits three books.

<form method="post" action="/Home/Create">

    <input type="text" name="[0].Title" value="Curious George" />
    <input type="text" name="[0].Author" value="H.A. Rey" />
    <input type="text" name="[0].DatePublished" value="2/23/1973" />
    
    <input type="text" name="[1].Title" value="Code Complete" />
    <input type="text" name="[1].Author" value="Steve McConnell" />
    <input type="text" name="[1].DatePublished" value="6/9/2004" />
    
    <input type="text" name="[2].Title" value="The Two Towers" />
    <input type="text" name="[2].Author" value="JRR Tolkien" />
    <input type="text" name="[2].DatePublished" value="6/1/2005" />
    
    <input type="submit" />
</form>

Note that the index must be an unbroken sequence of integers starting at 0 and increasing by 1 for each element.

The new expression based helpers in ASP.NET MVC 2 will produce the correct format within a for loop. Here’s an example of a view that outputs this format:

<%@ Page Inherits="ViewPage<IList<Book>>" %>

<% for (int i = 0; i < 3; i++) { %>

  <%: Html.TextBoxFor(m => m[i].Title) %>
  <%: Html.TextBoxFor(m => m[i].Author) %>
  <%: Html.TextBoxFor(m => m[i].DatePublished) %> 

<% } %>

It also works with our templated helpers. For example, we can take the part inside the for loop and put it in a Books.ascx editor template.

<%@ Control Inherits="ViewUserControl<Book>" %>

<%: Html.TextBoxFor(m => m.Title) %>
<%: Html.TextBoxFor(m => m.Author) %>
<%: Html.TextBoxFor(m => m.DatePublished) %> 

Just add a folder named EditorTemplates within the Views/Shared folder and add Books.ascx to this folder.

Now change the original view to look like:

<%@ Page Inherits="ViewPage<IList<Book>>" %>

<% for (int i = 0; i < 3; i++) { %>

  <%: Html.EditorFor(m => m[i]) %>

<% } %>

Non-Sequential Indices

Well that’s all great and all, but what happens when you can’t guarantee that the submitted values will maintain a sequential index? For example, suppose you want to allow deleting rows before submitting a list of books via JavaScript.

The good news is that by introducing an extra hidden input, you can allow for arbitrary indices. In the example below, we provide a hidden input with the .Index suffix for each item we need to bind to the list. The name of each of these hidden inputs are the same, so as described earlier, this will give the model binder a nice collection of indices to look for when binding to the list.

<form method="post" action="/Home/Create">

    <input type="hidden" name="products.Index" value="cold" />
    <input type="text" name="products[cold].Name" value="Beer" />
    <input type="text" name="products[cold].Price" value="7.32" />
    
    <input type="hidden" name="products.Index" value="123" />
    <input type="text" name="products[123].Name" value="Chips" />
    <input type="text" name="products[123].Price" value="2.23" />
    
    <input type="hidden" name="products.Index" value="caliente" />
    <input type="text" name="products[caliente].Name" value="Salsa" />
    <input type="text" name="products[caliente].Price" value="1.23" />
    
    <input type="submit" />
</form>

Unfortunately, we don’t have a helper for generating these hidden inputs. However, I’ve hacked together an extension method which can render this out for you.

When you’re creating a form to bind a list, add the following hidden input and it will add the appropriate hidden input to allow for a broken sequence of indices. Use at your own risk!I’ve only tested this in a couple of scenarios. I’ve included a sample project with multiple samples of binding to a list which includes the source code for this helper.

<%: Html.HiddenIndexerInputForModel() %>

This is something we may consider adding to a future version of ASP.NET MVC. In the meanwhile, give it a whirl and let us know how it works out for you.

Found a typo or error? Suggest an edit! If accepted, your contribution is listed automatically here.

Comments

avatar

131 responses

  1. Avatar for Russell Garner
    Russell Garner October 23rd, 2008

    I recently wrote a content moderation system using MonoRail which used a similar binding strategy. I was wondering if/when ASP.NET MVC would support it. It has a similar syntax to your example, although it only deals with arrays rather than ILists (fair enough really - you're only going to have had a fixed number of things posted back).
    The use case for us was this: moderators need to lock and work on a batch of 10 blog comments/forum posts at once. They accept/reject this content by selecting an action from a drop down, and can amend the content to make it suitable for publication. Once this is done, all 10 items - along with the actions taken - are posted back to the server. An appropriate ModerationAction DTO is used to pull this data back.
    If this kind of functionality had not existed in MonoRail, we'd have had to write it (it was a non-negotiable use case), so I'm pretty pleased to see ASP.NET MVC is getting it. As to the lack of helpers here, I'm not sure that's huge. I got by just generating the [indexes] from the (NVelocity) view with a variable.

  2. Avatar for Gauthier Segay
    Gauthier Segay October 23rd, 2008

    Does the hidden index field is mandatory?
    As said by Russel Garner, MonoRail implementation is similar but doesn't need that hint, it doesn't feel usefull to put hidden index fields in the view.
    Also, will the default binder work on composite types containing arrays/lists? I've a similar use case in MonoRail where I bind array of DTO themselves containing array of enumeration values or integral values, it seems the MonoRail binder can work with any level of deepness, but I'm unsure with ASP.NET MVC's DefaultModelBinder (especially if the hidden index thing is mandatory).
    I guess I've to try it out :)
    Last thing, is there anything in the HTTP & HTML spec that ensure that form values would be sent in the same order as displayed in HTML? I'm just worried that there could be issues with proxy or exotic browser settings...

  3. Avatar for Andrew
    Andrew October 23rd, 2008

    Thanks so much for this, been waiting since beta was released to figure out how to do this!!

  4. Avatar for dmitry39
    dmitry39 October 23rd, 2008

    great article, as allways, thx

  5. Avatar for Paul
    Paul October 23rd, 2008

    Hi Phil,
    Any chance of a sentence or two on why the hidden index is needed?
    Regards,
    Paul

  6. Avatar for Matt J
    Matt J October 23rd, 2008

    Hi Phil,
    Great article, glad that someone finally documented this from M$ - but now that I'm using the DefaultModelBinder it's forced me to come away from using a few custom model binders I had that basically handled "Linq to SQL" objects, and I like the clean approach. Only problem is (this might be a tiny bit off-topic) that I don't think the DefaultModelBinder will handle Nullable properties on a Type that it's binding to - in my instance, it's a nullable foreign key reference (Guid) that always comes back as populated (default(Guid)) - leaving me with ForeignKeyReferenceAlreadyHasValueException's

  7. Avatar for Melvyn Harbour
    Melvyn Harbour October 23rd, 2008

    Phil,
    There's one potential problem with the suggested way of using the name attribute in that way surely. In the HTML 4.0 spec, the '[' and ']' characters are not part of the accepted list of characters for the name attribute. See the specification. If you're in XHTML, it shouldn't be a problem as the name attribute is specified as CDATA, but it is an important difference between the two. It means that we are now restricted to using XHTML, not necessarily a bad thing, but worth remembering since MVC does allow us fine grained control over the (X)HTML.

  8. Avatar for Jonathon Wilson
    Jonathon Wilson October 23rd, 2008

    Thanks for posting this -- I've been searching for various solutions to this (List of complex objects) for a while. In one case, I ended up doing something very similar to what you described, indexes on the fields, but using a custom model binder to recompose the list. In a second case, I kept a backing javascript object model in the browser, and simply provided a single field with the JSON of my serialized list, and deserialized in a model binder. That was definitely less code, but has the dependency on javascript (which was fine in my particular case). I'll take a look at the way you've described.

  9. Avatar for Vladan Strigo
    Vladan Strigo October 23rd, 2008

    Phil,
    Could you tell me for extensibility of binding in beta... I made my own FetchAndBindAttribute in P5, and now want to convert it to beta. Because of this function:
    private static Predicate<string> GetPropertyFilter(ParameterInfo parameterInfo) {
    BindAttribute attr = (BindAttribute)Attribute.GetCustomAttribute(parameterInfo, typeof(BindAttribute));
    return (attr != null) ? (Predicate<string>)attr.IsPropertyAllowed : null;
    }
    My natural idea was that my attribute should inherit from BindAttribute. However... BindAttribute is sealed?!?!?!!?!?

    Any ideas?
    Thnx!
    Vladan

  10. Avatar for Ben Hart
    Ben Hart October 23rd, 2008

    Hi Phil
    Very interesting. We've rolled our own similar solution... Simlar to what's already been asked, how is the index as defined in the value reflected in the list once posted? If we posted the sample above with index 1 missing, would the parameter have a list of length 3, with a null at index 1?
    I should play around and find out myself, just feeling lazy on Friday...
    Thanks! Ben

  11. Avatar for haacked
    haacked October 23rd, 2008

    @Melvyn I don't see anything in the HTML spec disallowing "[" characters in the name. You posted a link to something about the name of Frames, which has nothing to do with this. Did you have an updated link?

  12. Avatar for Melvyn Harbour
    Melvyn Harbour October 23rd, 2008

    That's strange - it should be a link to section 6.2 of the HTML spec (SGML basic types). I've realised after a bit of more detailed reading that I made a slight mistake. The line in the spec says that:
    "ID and NAME tokens must begin with a letter ([A-Za-z]) and may be followed by any number of letters, digits ([0-9]), hyphens ("-"), underscores ("_"), colons (":"), and periods (".")."
    However if you look at the definition of the input element, it's name attribute is marked as CDATA, not NAME (confusingly!). So actually nothing to worry about and XHTML and HTML appear to be consistent after all!

  13. Avatar for levib
    levib October 24th, 2008

    Phil asked me to take a look at the comments and to give some feedback. Hopefully this will answer some of the questions. :)
    @Gauthier - At the moment, the hidden index field is mandatory for binding lists of complex types (e.g. types that aren't structs or strings). This is due to a current limitation of the IValueProvider interface. We're considering changing the IValueProvider to make it slightly more powerful, which will negate the need for the hidden field. Also, AFAIK the HTML forms spec doesn't mandate an order, but in practice all browsers post the values in the order in which they appear in the document.
    @Matt - Can you provide a simple repro of the problem you're experiencing? We've gone to great lengths to make sure that nullable types work properly, but it's possible that our tests missed something.
    @Vladan - What are you trying to do here? The [Bind] attribute is sealed because it's a simple metadata attribute; there should be no need to subclass it. Did you instead mean to subclass the abstract CustomModelBinderAttribute type?
    @Ben - The index in the form is distinct from the index in the generated list. The index in the form is allowed to be any arbitrary string, but we'll always convert these to a zero-based list. It's the ordering that matters.
    @Melvyn - I've been hitting my head against a wall trying to read the spec. Suffice it to say that DTDs aren't my native tongue. :) At any rate, note that at the moment we don't have helpers that generate the [] syntax (and in fact, we have an open bug regarding the fact that ViewData.Eval() has its own syntax for specifying indexes). Also, note that the MVC HTML helpers are actually XHTML helpers. Some of the helpers do not produce valid HTML 4.01, but they all [should] produce valid XHTML 1.0.

  14. Avatar for haacked
    haacked October 24th, 2008

    @Melvyn Thanks for following up! I appreciate that. :)

  15. Avatar for Vladan Strigo
    Vladan Strigo October 24th, 2008

    Levib/Phil,
    I am trying to roll out my own impl. which has an additional parameter called FetchBehavior.
    Now, what I want is when someone defines a [FetchAndBind] attribute that it does everything [Bind] does and more (basically gets also a new FetchBehavior param and assigns a special kind of IBinder).
    The problem is that in methods:

    private static string GetFieldPrefix(ParameterInfo parameterInfo) {
    BindAttribute attr = (BindAttribute)Attribute.GetCustomAttribute(parameterInfo, typeof(BindAttribute));
    return ((attr != null) && (attr.Prefix != null)) ? attr.Prefix : parameterInfo.Name;
    }
    private static Predicate<string> GetPropertyFilter(ParameterInfo parameterInfo) {
    BindAttribute attr = (BindAttribute)Attribute.GetCustomAttribute(parameterInfo, typeof(BindAttribute));
    return (attr != null) ? (Predicate<string>)attr.IsPropertyAllowed : null;
    }

    your relying on an direct implementation of BindAttribute. Now, if I want to reuse the logic of IsPropertyAllowed and ModelName, my attribute must subclass BindAttribute. And that cannot be done.
    Is that any clearer? Please let me know if I was not able to explain, I will create a code sample of what I want to achieve.

    Thanks!

    Vladan

  16. Avatar for Vladan Strigo
    Vladan Strigo October 24th, 2008

    Also... the alternative (which I've implemented now) is that I send include/exclude properties lists and prefix to the constructor of customer binder, and in the binder itself execute the logic of those 2 functions manually.
    As you can imagine... its a hack.

    Thanks!
    Vladan

  17. Avatar for Ricky Supit
    Ricky Supit October 24th, 2008

    @Vladan: What I did is to create a new ModelBindingContext and pass property filter delegate like the following:
    BindAttribute bindAttr = new BindAttribute() { Exclude = this.Exclude, Include = this.Include };
    propFilter = (propName) =>
    bindAttr.IsPropertyAllowed(propName) && bindingContext.ShouldUpdateProperty(propName);
    It helps if at least the static version of IsPropertyAllowed be made public.
    Here is my implementation of CslaBindAttribute: www.codeplex.com/.../ProjectReleases.aspx
    Ricky

  18. Avatar for Joshua
    Joshua October 24th, 2008

    Would this sort of thing work for types with their own nested collections? Say as an example you had a bunch of products with categories you wanted to mass update. Would something along these lines work?



    <form method="post" action="/Home/UpdateProducts">



    <input type="hidden" name="products.Index" value="0" />

    <input name="products[0].Name" value="Beer" />

    <input name="products[0].Cataogry[0]" value="Drink" />

    <input name="products[0].Cataogry[1]" value="Alcoholic" />



    <input type="hidden" name="products.Index" value="1" />

    <input name="products[1].Name" value="Chips" />

    <input name="products[1].Cataogry[0]" value="Food" />



    <input type="hidden" name="products.Index" value="2" />

    <input name="products[2].Name" value="Salsa" />

    <input name="products[2].Cataogry[0]" value="Food" />

    <input name="products[2].Cataogry[1]" value="Condiment" />



    <input type="submit" value="Submit Query" />

    </form>

  19. Avatar for Vladan Strigo
    Vladan Strigo October 26th, 2008

    @Ricky,
    Your doing exactly the same thing I am. The only difference is that your custom attribute *is* your binder (implements binder interface and inherits from custom binder attribute) as well (which IMO from SRP perspective is not a good thing).
    Here is my implementation (you will notice the issue I am having in the Binder itself):
    akuaproject.googlecode.com/.../...BindAttribute.cs
    akuaproject.googlecode.com/.../...cherAndBinder.cs
    Notice:
    var hackedBindingContext = _Recreate_Binding_Context_Because_of_SEALED_BindAttribute_in_Beta(bindingContext);
    in BindModel and the function itself from above:
    private ModelBindingContext _Recreate_Binding_Context_Because_of_SEALED_BindAttribute_in_Beta(ModelBindingContext currentBindingContext)
    {
    return new ModelBindingContext(currentBindingContext,
    currentBindingContext.ValueProvider,
    currentBindingContext.ModelType,
    _GetPrefixOrModelName(currentBindingContext.ModelName),
    () => currentBindingContext.Model,
    currentBindingContext.ModelState,
    _IsPropertyAllowed);
    }
    private string _GetPrefixOrModelName(string currentModelName)
    {
    return (string.IsNullOrEmpty(_prefix)) ? currentModelName : _prefix;
    }
    private bool _IsPropertyAllowed(string propertyName)
    {
    var includeProperties = StringHelper.SplitString(_includeProperties);
    var excludeProperties = StringHelper.SplitString(_excludeProperties);
    // We allow a property to be bound if its both in the include list AND not in the exclude list.
    // An empty include list implies all properties are allowed.
    // An empty exclude list implies no properties are disallowed.
    bool includeProperty = (includeProperties == null) || (includeProperties.Length == 0) || includeProperties.Contains(propertyName, StringComparer.OrdinalIgnoreCase);
    bool excludeProperty = (excludeProperties != null) && excludeProperties.Contains(propertyName, StringComparer.OrdinalIgnoreCase);
    return includeProperty && !excludeProperty;
    }

    This would be not needed if the BindAttr was not sealed.

    Any thoughts?

    Vladan

  20. Avatar for Brett
    Brett November 12th, 2008

    Can you add the Include / Exclude to the list?
    Getting the stack overflow on my list. Assuming its because of nested objects of same type? So i want to restrict which properties it sets.
    So in your example:
    public ActionResult UpdateProducts(
    [Bind(Include = "Name, Price")]IList<product> products) {
    return View(products);
    }

  21. Avatar for haacked
    haacked November 12th, 2008

    @Brett Yes you can do it.

  22. Avatar for Trevor
    Trevor November 12th, 2008

    No matter what I do, when I try this method I get a stack overflow exception. Seems it finds an infinite loop somewhere. Is there an update to this that I am perhaps missing?
    Thanks,
    Trevor

  23. Avatar for Brett
    Brett November 12th, 2008

    @Trevor
    Me too. Trying to figure out whats causing it.
    I noticed this:
    www.codeplex.com/.../View.aspx?WorkItemId=2540
    Is there a work around example we can get? Even with Bind include narrowing down my list it still causes it.
    Thanks.

  24. Avatar for Brett
    Brett November 12th, 2008

    Ok I found solution to our problem. I guess the Bind(include doesnt work on the list. You have to place it directly on the object class thats in your list. So in his example.
    public ActionResult UpdateProducts(
    IList products) {
    return View(products);
    }
    [Bind(Include = "Name, Price")]
    public class Product {
    public string Name { get; set; }
    public decimal Price { get; set; }
    }
    Now i dont get stack overflow. Hope it helps someone.
    Brett

  25. Avatar for Trevor
    Trevor November 13th, 2008

    @Brett
    Thanks! That was a big help. Although it only worked when I had a generic list, so instead of:
    public ActionResult UpdateProducts(IList products)
    I have:
    public ActionResult UpdateProducts(IList<product> products)
    Otherwise I just get an empty list.

  26. Avatar for Trevor
    Trevor November 13th, 2008

    whoops, I mean:
    public ActionResult UpdateProducts(IList<product> products)
    could have sworn I typed that, but it didn't go in the comments

  27. Avatar for Trevor
    Trevor November 13th, 2008

    OK. This is weird. I guess the editor doesn't like angle brackets:
    public ActionResult UpdateProducts(IList<Product> products)

  28. Avatar for Hassan
    Hassan November 18th, 2008

    How about if i use a HTML.ListBox that submit a List of EntityID and EntityName? Is there any way to do this with DefaultModelBinder without registering Custom Model Binder?

  29. Avatar for KevinUK
    KevinUK November 25th, 2008

    I am trying to do similar to what Joshua has suggested.
    Lets say in the save method I am just expecting a single Product but one of it's properties is an IList of categories and each category has several properties.
    My edit form displays the product and loops through each category displaying each category. When I come to save the form, Product.Category is null when I expect 2 items in the collection!

    <%=Html.Hidden("product.Index",i) %>
    <%=Html.Hidden("product.Category["+i+"].Id", cat.Id)%>
    <%=Html.TextArea("product.Category["+i+"].Name", cat.Name)%>

    HTML rendered:

    <input id="product.Index" name="product.Index" type="hidden" value="0" />
    <input id="product.Category[0].Id" name="product.Category[0].Id" type="hidden" value="1" />
    <textarea cols="20" id="product.Category[0].Name" name="product.Category[0].Name" rows="2">

    I can make this work if I pass through an extra parameter of IList<category> category and change the above code accordingly but why won't this code work?
    Thanks!

  30. Avatar for KevinUK
    KevinUK November 30th, 2008

    I have fixed my issue. This line needed correcting to:
    <%=Html.Hidden("product.Category.Index",i) %>

  31. Avatar for jowen81
    jowen81 December 8th, 2008

    I was having an issue with the DefaultModelBinder in the Beta 1 release when using Linq to SQL objects and the object contained an EntitySet<> property. The ModelState property would remain valid, but the entity set would never get updated. Today I discovered what was actually happening, the DefaultModelBinder was adding values directly to the entity set and then setting the entity set reference to itself - which for some reason leaves no entities in the set.
    Pseudo Code of what's happening in the DefaultModelBinder:

    var list = BusinessObject.ObjectList;
    list.add(new {});
    ...
    BusinessObject.ObjectList = list;

    To fix the problem, I extended the DefaultModelBinder's BindModelCore method and added the additional check to see if the bindingContext.Model and the propertyResult.Value both contained a reference to the same object.

    if (propertyResult.Value != null)
    {
    if (!property.IsReadOnly
    // don't set if the property was updated directly
    // E.g. elements added directly to a collection reference.
    && !ReferenceEquals(property.GetValue(bindingContext.Model), propertyResult.Value))
    {
    shouldCallSetValue = true;
    }
    }
    else
    {
    ...

    Is anyone else having this problem? Is there a better way to handle this?

  32. Avatar for Graham
    Graham December 14th, 2008

    Thank you Phil!
    Absolutely made my day.

  33. Avatar for Max
    Max January 1st, 2009

    Very interesting feature, however it has its flaws.
    Be sure not to use the Html.Hidden Method to generate the hidden inputs for the Index, as it will cause a NullReferenceException if the form is resubmitted after validation. See http://forums.asp.net/t/1344517.aspx for more details.
    Has anyone a working example of the question that Joshua asked? Is this actually possible at this moment or will it be possible in future versions of ASP.NET MVC?

  34. Avatar for justin
    justin January 6th, 2009

    I just posted my take on doing variable list binding here:
    justsimplecode.com/.../...ists-in-asp.net-mvc.aspx
    please let me know what you think, thanks.

  35. Avatar for jason
    jason January 7th, 2009

    My prediction: Asp.Net Mvc will be just as bloated as web-forms, and twice the amount of "hacks" to get it running.

  36. Avatar for Jonas
    Jonas January 13th, 2009

    Hi,
    Very nice but I can't get the Action to return the class I specified, even though the data is available in the Request.Form collection, and also accessible if I use following method signature:
    public ActionResult Edit(FormCollection items)
    I would like it to look like this but then items returns null.
    public ActionResult Edit(IList<MyItems> items)
    Any suggestions?
    Brgds
    Jonas

  37. Avatar for Rich Urwin
    Rich Urwin January 24th, 2009

    Hi,
    Is there any way of passing custom parameters / delegates to a ModelBinder?
    The reason is, I'm using DevExpres's XPO ORM which (like most other ORMSs) uses sessions for object retrieval. If I want to set an XPO object as a property on another XPO object, I can create my custom binders to create the property/retrieve it from the DB, however, when doing this, I need to use the same ORM session as the parent object to avoid session mixing exceptions - but I can't obtain this session from anywhere because you can't (as far as I can tell) pass custom parameters into the ModelBinders.
    The only way I can see to do this would be to either augment the binding mechanism to pass it through when calling UpdateModel from the controller, or better still, augment it to pass in a delegate to do the retrieval.
    These are both rather messy and ideally any session-related code should stay in the data-access layer, but I can't see a better way.
    Anyone got any ideas?
    Rich

  38. Avatar for Bal
    Bal January 27th, 2009

    Is this feature still supported in the release candidate? I had it working in MVC Beta but after upgrading, it does not work. The collection is simply null in the action method.

  39. Avatar for Dan Miser
    Dan Miser January 27th, 2009

    Seconded on Bal's observation. I upgraded my Beta site to RC1, and the binding on the list no longer works.

  40. Avatar for Dan Miser
    Dan Miser January 28th, 2009

    My post on the asp.net mvc forums hasn't shown up yet. It appears the change that was made for RC1 was that the indexing of elements starts at zero, and counts up. At least that's my first take rummaging through the source.

  41. Avatar for Bal
    Bal February 8th, 2009

    yes, for anybody else thats comes accross this, your indexing should start from zero and be sequential in RC1. In beta the only requirement was that the index was consistent between related elements.

  42. Avatar for Carlos Sobrinho
    Carlos Sobrinho February 14th, 2009

    Hi there,
    I'm currently writing a custom ModelBinder for ISet<> collections.
    I would like to make UpdateModel update my ISet<> models.
    When I pass a entity Id < 0, it should create a new one.
    My problem is, is it possible to access the string[] includeProperties, string[] excludeProperties passed in the UpdateModel inside the ModelBinder?
    I need to insure that only some properties should be updated and I won't want to do: "entity[2].Id", "entity[2].Code", etc because I don't know if the index is 2 or some other value.
    Rather, I think "entity.Id", "entity.Code" or even better "entity[].Id", "entity[].Code" would be great for specifying the include and exclude properties for collections.
    What do you think? Any pointer on how to achieve this?

  43. Avatar for Huggy
    Huggy March 4th, 2009

    As jowen81 implied at
    haacked.com/.../model-binding-to-a-list.aspx#70052
    DefaultModelBinder does not automatically bind the form values to EntitySet<Object> from Linq-to-Sql whereas it can do it on List<Object> collection.
    Are there any shortcut to make this working?

  44. Avatar for faffy fuck
    faffy fuck March 15th, 2009

    We tried this here at work a little different, however it backfired and now someone here has a repeater stuck up his pooper. Now what. Can anyone help?

  45. Avatar for Jose Marmolejos
    Jose Marmolejos January 27th, 2010

    Thanks for the tip man, it really simplified some tasks I was doing manually and saying WTF am i doing everytime I had to. The only thing is that I think you should update your article to reflect what is being pointed out in this comment: haacked.com/.../model-binding-to-a-list.aspx#70815

  46. Avatar for MIkael Syska
    MIkael Syska January 28th, 2010

    Hi,
    Are there any news here? What about asp.net mvc 2 ?
    mvh

  47. Avatar for dario-g
    dario-g February 24th, 2010

    Yeap. I'm waiting for the same :) Phill, can you post something about changes in mvc 2?

  48. Avatar for Robert Koritnik
    Robert Koritnik March 8th, 2010

    Anyone asking about MVC 2 here's the answer. I'm working on an app that uses Asp.net MVC 2 RC2 and the BEST thing is, this technique still works as in previous version. I'm able to bind complex objects to a List<T>.

  49. Avatar for Tyler
    Tyler March 20th, 2010

    I upgraded to MVC RC2, and it looks like binding using arbitrary indexes is broken (your example above being "products[cold].Name"). You now HAVE to bind in sequential order, starting from 0. Was that an intentional change? It broke several of my forms.

  50. Avatar for haacked
    haacked April 8th, 2010

    @Tyler, that was an intentional change. But ASP.NET MVC 2 has brought that behavior back.

  51. Avatar for Andreas
    Andreas May 13th, 2010

    Hi,
    Nice article and great examples.
    I have a question for all of you.
    The "EditorTemplate And ViewModel" example demonstrates how /HiddenIndexerInputForModel/ makes it possible to model bind a non sequential collection of rows, thus allowing for javascript row deletion. That is great.
    But how would you implement a javascript add?
    A straight forward solution could look something like this:
    $("#addRowLink").livequery('click', function (event) {
    event.preventDefault();
    var guid = jQuery.Guid.New();
    var row = '<tr><td><input type="text" value="" name="Books[' + guid + '].Title" id="Books_' + guid + '__Title">.......';
    $(".mytable tbody").prepend(newRowHtml);
    }
    Here I use a guid as the index value; ensuring the newly added row can be uniquely identified.
    This solution works, but it seems smelly that the javascript contains a html string, that will have to be updated if the view or viewmodel structure changes.
    Is there a better way to do this - e.g. generating a html-string variable on the server side?


  52. Avatar for Michael
    Michael May 24th, 2010

    I see that this article is pretty old, is this still the best solution or do MVC2 provide some new features.
    Michael

  53. Avatar for Adam
    Adam June 12th, 2010

    Oi Haack!
    How come TryUpdateModel doesn't bind to a list?
    e.g.
    var stuffs = _db.Stuff.Where(p => knownIds.Contains(p.stuffId)).OrderBy(p => p.stuffId);
    if (TryUpdateModel(stuffs)) {
    // Updated objects, not new ones!
    }
    else {
    }
    I don't need saving from myself...
    Also! Wouldn't the metadata model would be better if you had a metadata register. Then you don't (always) need to use data-annotations / attributes when using strongly typed helpers.
    e.g.
    MetaData.MataDataValues[typeof(Chilli)]["HotnessRating"] = "Hotness Rating";
    Or using one of those dynamic doo-dars perhaps for people who don't like straight squared backets.
    MetaData.MataDataValues[typeof(Chilli)].HotnessRating = "Hotness Rating";
    Don't get me wrong guys if you like Data Annotations, great. If you use IDataErrorInfo and you've got some wierd validation going on, the above would work great too and it's tidy. Kinda looks like how ModelBinder dictionaries work.
    Also!
    HtmlHelper is aweful. Most of the time you have to type a gazillion dots just to get basic things you need. Like the HttpContextBase or HttpRequestBase. The C# monks want to burn me at stake for dis-obeying the commandment of demiter.
    If you could get at querystring variables through the RouteData that'd be quite good.
    HtmlHelper<T> is also aweful. If you want to write expression based helpers you have to go all over the place to the job. Use some static expression helper, then some metadata or something. How come this isn't all in the same place since it's all related.
    Mr Phil, you're normally meticulous, but a few small parts of MVC2 seem like they've been haacked together. What went wrong? I'm sure it was probably Brad's fault.

  54. Avatar for helal
    helal July 22nd, 2010

    Can we use a 2 dimensional array to bind it in our form?
    In my model i have this:
    public class EmailDetails
    {
    public string[] emailTo { get; set; }
    public string[,] emailFieldValues { get; set; }
    }
    so in my form to bind the emailTo is simple and it works:
    <input type="text" id="Text1" title=" " name="emailTo" maxlength="100" class="required email txt userInput" />

    I need a 2 dimensional array so that i can match the value with something.
    Is that possible?

  55. Avatar for George
    George August 11th, 2010

    What if you're wanting to display a list of options outside the scope of the Model you're representing, ie. a MultiSelectList assigning List<Interest> to User.Interests. Simply passing User.Interests to the control leaves it unaware of anything other than that User's selection, and passing it List<Interest> leaves it unaware of the users selection!

  56. Avatar for James
    James August 20th, 2010

    Thanks for the tips Phil. I realise this is a very old post, but it still comes up in Google, so I thought I'd throw in some help for anyone who is maybe doing what I'm doing.
    Here is a function that will serialize a javascript object or array to a form data representation so that it can be bound by MVC model binders as you describe:

    function encodeData( data, prefix )
    {
    var ret = "";
    var pre = prefix ? prefix : "";
    if( data.constructor === Array )
    {
    for( index in data )
    {
    ret += encodeData(data[index], pre+'['+index+']');
    }
    }
    else if( data.constructor === Object )
    {
    if( pre != "" ) pre += '.';

    for( key in data )
    {
    ret += encodeData(data[key], pre+key);
    }
    }
    else return encodeURIComponent(pre)+'='+encodeURIComponent(data)+'&';

    return ret;
    }

  57. Avatar for Serhiy
    Serhiy August 21st, 2010

    Help me please! My compiler said that syntax is invalid here "<%: ". It really don't like ":" after "<%". How can I fix this? Thank you.

  58. Avatar for Cory Fowler
    Cory Fowler August 31st, 2010

    I'm trying to get this scenario to work using jQuery.


    I'm using $('#myForm').serialize(); to serialize the form which is formatting the values like this 'ints=1&ints=4&ints=2&ints=8'.


    To perform the asynchronous action I am using jQuery.ajax ($.ajax) which looks like this:



    $.ajax({
    type: 'GET', // I'm retrieving a list of values for update.
    cache: false,
    url: url,
    dataType: 'json',
    data: $('#myForm').serialize(),
    success: MarkSelectedCheckboxes(data)
    });

    the signature for my controller action looks like this:



    public ActionResult GetCurrentlyCheckedBoxes(ICollection<string> checkBoxesInView, ICollection<string> CheckedBoxesInView, string RecordIdentifier)

    I don't seem to be getting the results back in an expected manner. Any thoughts? Thanks in Advance.

  59. Avatar for Cory Fowler
    Cory Fowler August 31st, 2010

    My post is a prime example of how over architecture can lead to very complex solutions, I opted to return a full result set based solely on the RecordIdentifier and don't have any more issues.
    Thanks,
    Cory

  60. Avatar for Slav
    Slav October 31st, 2010

    Thanks Phil! That was exactly what I was looking for.

  61. Avatar for Sylon
    Sylon November 7th, 2010

    Hi Phil
    would be good if you are able to answer my question stackoverflow.com/... about this post.
    Thanks!

  62. Avatar for Mark
    Mark January 5th, 2011

    I appreciate this is now a little old but I was just trying this and noticed something very odd happen on the editor template sample specifically.
    When deleteing a record and hitting create the submitted values display correctly as to what books should be posted back but HTML form does not - the record after the one that is repeated displays twice and the last item is dropped off.
    Seems very odd and I can see no reason for it. Everything else suggests the list of books was posted back correctly.

  63. Avatar for Terry
    Terry February 4th, 2011

    If we had to do some custom validation in the Action, is there a proper way of determining the input id when using ModelState.AddModelError? I'm currently hard coding it after looking at the HTML source outputted on the form rendering, but assuming there has to be a better/proper way?

  64. Avatar for Ignacio Fuentes
    Ignacio Fuentes March 8th, 2011

    Is this working in mvc 3?
    Im getting an error when I add the
    @Html.HiddenIndexerInputForModel() to my editorTemplate

    even though i do get Intellisense for the Helper its telling me that the method is undefined.

  65. Avatar for Kefke
    Kefke April 17th, 2011

    Are the Non-Sequential Indices possible in MVC3 ?

  66. Avatar for haacked
    haacked April 18th, 2011

    @Kefke, Yes.

  67. Avatar for elperucho
    elperucho April 19th, 2011

    Es formidable, realmente impresionante, cada dia que aprendo mas asp.net mvc, veo que la programación es un un simple juego de armar y desarmar con mvc.
    Thank. Haack.

  68. Avatar for alexandros
    alexandros April 19th, 2011

    I have tried this example in the past (MVC2) and it worked fine.
    Now with MVC3 and Razor engine I get a "Index was out of range. Must be non-negative and less than the size of the collection."
    Has anyone seen/tackled this?

  69. Avatar for Mike
    Mike April 27th, 2011

    If there is an example of this using MVC3 and Razor engine I would love to see it...I cannot seem to get this to work.

  70. Avatar for JeffM
    JeffM May 2nd, 2011

    Like Terry, I want to know how to properly use ModelState.AddModelError(key, errorMessage) with this. For example,
    ModelState.AddModelError("CategoryID", "Product category does not exist");
    doesn't work because it should be something like
    ModelState.AddModelError("products[42].CategoryID", "...");
    However, the index (42 in this example) doesn't seem to be available to the controller.
    Suggestion?

  71. Avatar for Madhu
    Madhu June 28th, 2011

    Great article.
    I was after this for half of the day and your solution worked for me. Many Thanks.
    Madhu

  72. Avatar for Josep Maria Vidal
    Josep Maria Vidal July 27th, 2011

    Hi there Phil.
    In your sample application, last option: Editor Template with ViewModel, if you delete second and fourth rows and then you click Create, when the page returns the third row is not correct.
    Have you experienced this effect too?
    How can we fix it?
    Thank you very much.

  73. Avatar for Aaron
    Aaron August 9th, 2011

    I am trying to use UpdateModel in the Controller.Edit HttpPost handler so that properties not included in the form will not be nulled out. I.e. the edit form only includes some properties of the entity that are editable. Upon saving the results these get nulled out. So I often fetch the original entity, and use UpdateModel on it to only update the provided fields. I am trying to modify the example code to work with this technique, but have yet to figure this out.

  74. Avatar for Andy Menon
    Andy Menon September 20th, 2011

    How do validations play out in this kind of a scenario?
    I built something like this, with a class that inherited from an EF model class (which obviously had some properties marked "required").
    The form rendered as expected, and the collection was bound successfully.
    But it was a all or none kind of a situation. The form would not allow me to submit unless I filled out all the required fields across all the rows. This was unacceptable to me as only the first row was mandatory, and rest of the rows were optional.
    How do we handle such cases?

  75. Avatar for Double Dummy
    Double Dummy December 6th, 2011

    Hi Phil,
    Are EF navigation properties two-way model bindable? They are collections of complex types.
    Thanks for this great article and a lot of other great articles, videos ... as well. They are never out of date!

  76. Avatar for Juan
    Juan January 4th, 2012

    Thanks for this nice post.
    lets suppose that the list of books are part of a buy order to order those books to any provider.
    we will list those books, and will select the provider from a combobox, to set the id of the provider that is a value for the whole list an not a value for each book.
    How do we do that?

  77. Avatar for lebarquero
    lebarquero January 10th, 2012

    Thank you for this post.
    I followed all the steps and everything are fine, but I have little problem, my method post's argument always return null. The argument is a viewmodel class with a list collection.
    I using MVC3 with razor engine.
    I'll apreciate any suggestion.
    Regards

  78. Avatar for comgiu
    comgiu February 1st, 2012

    if u need to select with jquery a textbox u need to escape it
    like this $("#\\[0\\]_Title")

  79. Avatar for Leniel Macaferi
    Leniel Macaferi February 20th, 2012

    Hey Haacked,
    You're the guy... :-)
    Thanks for posting this my friend. Helped a lot.
    Keep posting more about ASP.NET MVC and NuGet. Amazing technologies!
    Best wishes from Brazil.

  80. Avatar for Evan Larsen
    Evan Larsen April 30th, 2012

    4 years later and this is still very useful. Thanks for the post, this helped me greatly.

  81. Avatar for martin
    martin May 28th, 2012

    Can you please help me with this issue
    stackoverflow.com/...

  82. Avatar for Ja Lak
    Ja Lak June 25th, 2012

    This is great. I was wondering though how you would go about implementing validationsummary for each object in the list instead of one for all of them?

  83. Avatar for Kuke
    Kuke July 4th, 2012

    Many thanks for this post Phil!
    I am working with MVC3 and I've managed to bind complex models with your HiddenInputForModel although with some hacks of mine.
    So far I've bound say a Contract with a generic list property of ContractActions using as indexer Utc ticks.
    However I now stumbled on binding a level 2 complexity of type:
    Contract.ContractActions[222].ContractActionZones[4444],
    Contract.ContractActions[222].ContractActionZones[8383],
    Contract.ContractActions[222].ContractActionZones[6663]
    etc.
    When I set the indexers of ContractActionZones to 0, 1 etc they seem to bind properly to the controller and the ContractAction but not with the utc ticks (that are binding correctly so far the ContractActions).
    Has anyone of you managed to bind complex model within complex model? Am I missing something obvious?
    Thanks a lot!

  84. Avatar for Quickhorn
    Quickhorn July 9th, 2012

    Thank you so much! This is incredibly helpful. After days of trying to figure out how to assign my list back into my model, this is exactly what I was looking for.

  85. Avatar for Hampus Bengtsson
    Hampus Bengtsson July 23rd, 2012

    I too wonder how to get the validation messages displaying next to each item. The validation summary shows property errors, but I can't get them to show with something like [code]@Html.ValidationMessageFor(m => m.fooItems[i])[/code]

  86. Avatar for Reza Baiat
    Reza Baiat August 26th, 2012

    very thanks. So helpful. So great

  87. Avatar for Kate
    Kate September 10th, 2012

    Thanks! It helped me.

  88. Avatar for Mike
    Mike November 8th, 2012


    So at the end you mention the possibility of adding this to a future version of MVC. Any chance that happened?

  89. Avatar for hieunt
    hieunt November 14th, 2012

    thank you!

  90. Avatar for Carlos
    Carlos December 26th, 2012

     What i don't understand is who iterates using a for loop like this
    <% for (int i = 0; i < 3; i++) { %>when you have a list of object in your model ,can you do the same doing a foreach (var item in Model) { %>

  91. Avatar for Mrivasa
    Mrivasa January 2nd, 2013

    Very useful post.  How will you make your example work with unobtrusive validation?

  92. Avatar for Maxim Yefremov
    Maxim Yefremov January 25th, 2013

    I've noticed it too. The reason is indexing. If you are deleting the 3rd row before submiting you have 4 rows with hidden indexes: 0, 1, 3, 4. And when you submiting form something goes incorrect. But if before submiting you edit hidden indexes for last 2 rows and make them: indstead 3 - 2. Instead 4 - 3. And then submit. Here you got correct submiting result. So the the solution is to edit this indexes in javascript after delet clicked. But it's workaround. If someone bring more cute solution I will be happy)

  93. Avatar for AaronLS
    AaronLS February 19th, 2013

    Phil, has anything changed in MVC to allow support for binding to form post values with square brackets like those named "something[]"?  Some jquery libraries like x-editable/select2 do this, (probably because PHP has the opposite problem, it didn't treat multiple form field names as an array, but added this support only if you named them something liked "something[]" so some javascript tools follow that convention).  I can't even get [Bind(Include="somename[]")]ICollection<int> somename, ... to map the values, even though Request.Form.GetValues("value[]") works fine.

  94. Avatar for gorski
    gorski April 26th, 2013

    You made me understand this at last!!

  95. Avatar for prosperva
    prosperva May 10th, 2013

    Thank you for the post.

  96. Avatar for Meysam Fathee Panah
    Meysam Fathee Panah May 29th, 2013

    tnx

  97. Avatar for Bryon Lape
    Bryon Lape September 20th, 2013

    Anyone know how to do this kind of thing for check boxes?

  98. Avatar for sdfgsdfg
    sdfgsdfg October 3rd, 2013

    sdfgsdfgdfgsdfgsdfg

  99. Avatar for Leonardo
    Leonardo October 31st, 2013

    Great post!

  100. Avatar for Pradip
    Pradip December 31st, 2013

    How to use validations on the list?

  101. Avatar for Luca
    Luca February 7th, 2014

    With Port-Redirect-Get pattern, this will won't work. Validation messages generated by server side validation will appear out of place.

  102. Avatar for Taurin
    Taurin February 12th, 2014

    I just wanted you to know that the bit about setting a hidden index field saved me a ton of headache on my project. There were several times that my indices couldn't be sequential (for one reason or another) and it would CONSTANTLY break the form submission for one reason or another. This simple fix takes that problem away entirely. Thanks a lot!

  103. Avatar for Shashank
    Shashank February 18th, 2014

    What if the No of Item I have to add to list are not fixed....on user action another row is added by ajax call..how to maintain index for that?

  104. Avatar for Guest
    Guest July 17th, 2014

    You sample will not work for nested collection, for item like "Items[1].Items[1].Index", expected result is "Items[1].Items.Index", but code returns "Items.Items.Index".

    I made a quick fix:

    static Regex _stripIndexerRegex = new Regex(@"\[(?<index>\d+)\]", RegexOptions.Compiled | RegexOptions.RightToLeft);

    public static string GetIndexerFieldName(this TemplateInfo templateInfo)

    {

    string fieldName = templateInfo.GetFullHtmlFieldName("Index");

    var matches = _stripIndexerRegex.Matches(fieldName);

    if (matches.Count > 0)

    {

    var match = matches[0];

    fieldName = fieldName.Remove(match.Index, match.Length);

    }

    // fieldName = _stripIndexerRegex.Replace(fieldName, string.Empty);

    if (fieldName.StartsWith("."))

    {

    fieldName = fieldName.Substring(1);

    }

    return fieldName;

    }

  105. Avatar for Paweł Kondzior
    Paweł Kondzior July 17th, 2014

    You sample will not work for nested collection, for item like "Items[1].Items[1].Index", expected result is "Items[1].Items.Index", but code returns "Items.Items.Index".

    I made a quick fix:

    static Regex _stripIndexerRegex = new Regex(@"\[(?<index>\d+)\]", RegexOptions.Compiled | RegexOptions.RightToLeft);

    public static string GetIndexerFieldName(this TemplateInfo templateInfo)
    {
    string fieldName = templateInfo.GetFullHtmlFieldName("Index");
    var matches = _stripIndexerRegex.Matches(fieldName);
    if (matches.Count > 0)
    {
    var match = matches[0];
    fieldName = fieldName.Remove(match.Index, match.Length);
    }

    // fieldName = _stripIndexerRegex.Replace(fieldName, string.Empty);

    if (fieldName.StartsWith("."))
    {
    fieldName = fieldName.Substring(1);
    }

    return fieldName;
    }

  106. Avatar for Torleif Berger
    Torleif Berger October 28th, 2014

    You don't have an index in a foreach.

  107. Avatar for superjose
    superjose October 29th, 2014

    Thanks a million! This worked flawlessly!

  108. Avatar for Hi Ten
    Hi Ten November 5th, 2014

    Thanks for such neat & clear code..... I have implemented the same in my project but while rendering the editor template (.ascx). it shows all the model fields instead of what i listed in it... Any guesses...

  109. Avatar for ozbob
    ozbob December 4th, 2014

    Still relevant today MVC Model Binding still needs Array notation in POST parameters.

    There is an additional solution: http://stackoverflow.com/qu...

  110. Avatar for meb
    meb January 22nd, 2015

    Thanks, really helped me out. You would have thought something like name[0], name[1], etc. would have been a little more intuitive rather than the [0].name, [1].name, etc.

  111. Avatar for Guest
    Guest February 11th, 2015

    Thank you so much for your article. It helped me a lot with another exaxmple To build a dynamic one

  112. Avatar for lnanikian
    lnanikian February 11th, 2015

    Thank you for your article. IT helped me a lot with a knockout example To build in a dynamic scenario

  113. Avatar for Mr Mike Wat
    Mr Mike Wat February 20th, 2015

    in 2014 article is still on point as it reveals an important point about no sequential indexes.

  114. Avatar for segay
    segay March 8th, 2015

    Excellent work, Phil! I finally managed to successfully upgrade installation on my blog to 2.1.0.5 from 1.9.3 (all upgrade attempts to other releases were unsuccessfull).

  115. Avatar for aakash
    aakash March 17th, 2015

    Cannot apply indexing with [] to an expression of type 'System.Collections.Generic.IEnumerable<gamma.models.support>

  116. Avatar for Ejaz Qadir
    Ejaz Qadir April 2nd, 2015

    hi, my view form contains a start date (one field only) and dynamically generated list of arrival date and times. how can i bind the view page to post method. i will be receiving one start date entry and say 30 entries for arrival date.

  117. Avatar for Tim Mc
    Tim Mc July 13th, 2015

    Keep in mind that you will have to sometimes change the default "Prefix" if you're using a PartialView to render out the List or each element. Otherwise, your list elements just come out with IDs like "[0].ID" or "[0].Name".

    Razor:
    @{
    var templateInfo = ViewContext.ViewData.TemplateInfo;
    templateInfo.HtmlFieldPrefix = "Roles";
    }

    Then, in your POST controller action, just Bind to that collection:
    public ActionResult Edit(UserModel model, [Bind(Prefix = "Roles")] ICollection<userrolemodel> roles)

    This has come in handy several times when I have a complex form which needs to save values within collections as well as the root entity / model.

  118. Avatar for Alexander
    Alexander August 30th, 2015

    I use set of filters for grid, each filter control is like the thing in the article. I use javascript to disable/enable specific controls (so they are not included into input parameter's collection). However, for some reason not all types are properly parsed. I have "System.Type" type and it's null...

  119. Avatar for Carlos Pirela
    Carlos Pirela November 26th, 2015

    Great information, helped me solve an issue trying to post a model list with file input. Just had to add "multipart/form-data" to the <form> tag and HttpPostedFileBase file on the model class. Everything works!

  120. Avatar for thomas wu
    thomas wu January 4th, 2016

    Great article and thanks for the tip, it really helpful.

  121. Avatar for thomas wu
    thomas wu January 5th, 2016

    I got little problem, when i using Chrome Browser and click the back button,
    because the input with type="hidden" when dynamically set values didn't handled properly by the Chrome Browser.

    maybe we can change
    <input type="hidden" name="products.Index" value="my value"/>
    to
    <div style="display: none">
    <input type="hidden" name="products.Index" value="my value"/>
    </div>

  122. Avatar for thomas wu
    thomas wu January 5th, 2016

    I got little problem, when i using Chrome Browser and click the back button,
    because the input with type="hidden" when dynamically set values didn't handled properly by the Chrome Browser.

    maybe we can change
    <input type="hidden" name="products.Index" value="my value"/>
    to
    <div style="display: none">
    <input type="text" name="products.Index" value="my value"/>
    </div>

  123. Avatar for thomas wu
    thomas wu January 5th, 2016

    Great article and thanks for the tip,it really helpful.

    And I got a little problem, when i using Chrome Browser and click the back button,
    Because the input with type="hidden" when dynamically set values didn't handled properly by the Chrome Browser. (other Browser is OK)

    maybe we can change

    <input type="hidden" name="products.Index" value="my value"/>

    to

    <div style="display: none">
    <input type="text" name="products.Index" value="my value"/>
    </div>

  124. Avatar for David Robles
    David Robles January 14th, 2016

    Hi, thanks for this article, it has helped me a lot in some apps I've developed, since this article is from 2008 I just want to know if there is a simpler way to do this, since I've been using a lot of javascript to concatenate the elements names so they can be ready for the submit, also I've added delete items functionality but when you delete some item in the middle you have to rearrange indexes and do a lot of dirty work through javascript, maybe there is a new js framework that can help to simplify this process, any help will be appreciated. Thanks again for this well explained article.

    UPDATE

    Never mind, you're great I didn't read the --- Non-Sequential Indices --- Section of this.. again.. Legendary article.

  125. Avatar for Victor
    Victor May 18th, 2016

    very nice thks

  126. Avatar for Benjamin E.
    Benjamin E. August 4th, 2016

    Greateful for the post, however, how will the input values be passed to the model in controller to be save. in my case the model has one property that i wish to accept the inputs but to store them individually to the model.

  127. Avatar for Rafael Catani Santa Helena
    Rafael Catani Santa Helena November 11th, 2016

    Hi, I'm trying to get a list of objects in my class, but I'm not sure how to do that. To the controller, the values appear correct, but if I send a loaded list, only the list appears correct, all other fields of the modeling appear null or empty.
    What can I do to fix this?

    https://stackoverflow.com/q...

  128. Avatar for Atul Sahrawat
    Atul Sahrawat January 5th, 2018

    Thanks !! You made my day.

  129. Avatar for Jamie Introcaso
    Jamie Introcaso January 22nd, 2018

    Fantastic article. I keep coming back and pointing my coworkers to it. Thanks for this, Phil!

  130. Avatar for Kamalpreet Singh
    Kamalpreet Singh August 28th, 2018

    If every row has same value for name attribute (products.Index), form post will consider it as one element. How does it handle here?

  131. Avatar for Aaron T
    Aaron T October 16th, 2018

    Thank you, Phil Haack, for this, even a decade later, especially for the html example under Non-Sequential Indices!