0

How can I post nested data via a form submission into an ActionResult parameter? I've been attempting to implement a solution similar to the answer to this question but am not having much luck.

The section of the form in question is structured as follows:

<form method="post" action="/Product/Edit" class="tabs">
    <input name="Prices[1].Price" id="Prices_1__Price" value="9.99" type="text">
    <input name="Prices[1].Size2Price" id="Prices_1__Size2Price" value="0.00" type="text">
    <input name="Prices[1].Size3Price" id="Prices_1__Size3Price" value="0.00" type="text">
    <input name="Prices[2].Price" id="Prices_2__Price" value="5.00" type="text">
    <input name="Prices[2].Size2Price" id="Prices_2__Size2Price" value="0.00" type="text">
    <input name="Prices[2].Size3Price" id="Prices_2__Size3Price" value="0.00" type="text">
    <input name="Prices[3].Price" id="Prices_3__Price" value="0.00" type="text">
    <input name="Prices[3].Size2Price" id="Prices_3__Size2Price" value="0.00" type="text">
    <input name="Prices[3].Size3Price" id="Prices_3__Size3Price" value="0.00" type="text">
    <button type="submit">submit</button>
</form>

This is coming through in the log fine, with the posted data displaying as expected:

Form Submission Event: (BaseController:57-ish): 
{
    ...
    "Prices[1].Price": "9.9900",
    "Prices[1].Size2Price": "0.0000",
    "Prices[1].Size3Price": "0.0000",
    "Prices[2].Price": "5.5800",
    "Prices[2].Size2Price": "0.0000",
    "Prices[2].Size3Price": "0.0000",
    "Prices[3].Price": "0.0000",
    "Prices[3].Size2Price": "0.0000",
    "Prices[3].Size3Price": "0.0000",
    ...
}

In the Model, I've been trying variations to try to catch the collection of prices, the current attempt is as follows:

[DataContract]
public class EditedProductEntry
{
    [DataContract]
    public struct PriceCollection
    {
        [DataMember( Name = "Price" )]
        public string Price { get; set; }
        [DataMember( Name = "Size2Price" )]
        public string Size2Price { get; set; }
        [DataMember( Name = "Size3Price" )]
        public string Size3Price { get; set; }
    }

    ...

    [DataMember( Name = "Prices" )]
    public PriceCollection[] Prices { get; set; }

    ...
}

On the Controller side I have the "Edit" ActionResult which receives the "EditedProductEntry" data structure:

[HttpPost]
[Route( "Edit", Name = "Product_Edit" )]
public ActionResult Edit( EditedProductEntry post )
{
    ...
}

I've been fiddling about with the "post" parameter's structure attempting to have it accept the "Prices" collection but this has me stumped. The rest of the data is coming through fine & is populating the "EditedProductEntry" object, however the collection is resolute in remaining null.

I've tried catching an object[], EditedProductEntry[], ICollection, IEnumerable & have also tried specifying these as an additional parameter to the "Edit" Action but so far I've not had any luck.

Does anyone have any other ideas?

Community
  • 1
  • 1
  • 2
    Start the index from 0 instead of 1 or use non-sequential indices binding for model binding collections - http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx/ . I would recommend the second approach – Developer Feb 09 '17 at 17:07
  • 1
    DataContract and DataMember attributes are not required (and probably should be used, it's just adding noise to your code). – Erik Philips Feb 09 '17 at 18:07
  • Manually generating your inputs is crazy. If they are existing items, refer [this answer](http://stackoverflow.com/questions/30094047/html-table-to-ado-net-datatable/30094943#30094943), and if your dynamically adding/removing items in thew view, refer [this answer](http://stackoverflow.com/questions/28019793/submit-same-partial-view-called-multiple-times-data-to-controller/28081308#28081308) –  Feb 09 '17 at 20:44
  • @Developer, you should have posted that as an answer. You & Chetan were spot on. Thanks all. – N00b-a-Tron 9000 Feb 10 '17 at 09:27
  • But I strongly suggest you to have a look into non-sequential indices for binding collection. And as @StephenMuecke said, try not to generate it manually. – Developer Feb 10 '17 at 09:41
  • At the risk of inciting a discussion in the comments; the only auto-generation of models I've seen thus-far have been when linked directly to a database. The system I'm working on ties into an API used by several different products (which is why the attributes are there), although I have just found [this question](http://stackoverflow.com/questions/21611674/how-to-auto-generate-a-c-sharp-class-file-from-a-json-object-string) which suggests tools. Thanks for the suggestions, I'll continue looking into non-sequential indexing. – N00b-a-Tron 9000 Feb 10 '17 at 10:07

1 Answers1

1

I tried the same case on my local machine and figured out that the indexing of the control names is not correct.

The control names should be following zero based index and so the data which is being posted too.

The input controls should be declared as following.

<input name="Prices[0].Price" id="Prices_1__Price" value="9.99" type="text">
<input name="Prices[0].Size2Price" id="Prices_1__Size2Price" value="0.00" type="text">
<input name="Prices[0].Size3Price" id="Prices_1__Size3Price" value="0.00" type="text">
<input name="Prices[1].Price" id="Prices_2__Price" value="5.00" type="text">
<input name="Prices[1].Size2Price" id="Prices_2__Size2Price" value="0.00" type="text">
<input name="Prices[1].Size3Price" id="Prices_2__Size3Price" value="0.00" type="text">
<input name="Prices[2].Price" id="Prices_3__Price" value="0.00" type="text">
<input name="Prices[2].Size2Price" id="Prices_3__Size2Price" value="0.00" type="text">
<input name="Prices[2].Size3Price" id="Prices_3__Size3Price" value="0.00" type="text">

So the log file also will have following data.

"Prices[0].Price": "9.9900",
"Prices[0].Size2Price": "0.0000",
"Prices[0].Size3Price": "0.0000",
"Prices[1].Price": "5.5800",
"Prices[1].Size2Price": "0.0000",
"Prices[1].Size3Price": "0.0000",
"Prices[2].Price": "0.0000",
"Prices[2].Size2Price": "0.0000",
"Prices[2].Size3Price": "0.0000",

Making this change should resolve your issue.

Chetan
  • 6,711
  • 3
  • 22
  • 32
  • Argh, thanks to all who answered. You were correct about the indexing, I was being stupid & using the ID of the price level for the index instead of just passing it as a hidden field into the "PriceCollection" object. – N00b-a-Tron 9000 Feb 10 '17 at 09:28