0

Why isn't MVC able to bind my List of complex objects? I have read several examples on this topic and nothing has resolved the issue. Consider the following:


Complex Version

I have a ViewModel with a list of complex objects as a property:

public List<XMLVariable> XMLVariables { get; set; }

My View then binds this list of objects to controls:

        @for (int i = 0; i < Model.XMLVariables.Count(); i++)
        {
            @Html.HiddenFor(m => Model.XMLVariables[i].Name)
            @Html.TextBoxFor(m => Model.XMLVariables[i].Value)
        }

The view displays the variables just fine, but when I submit the form nothing happens. The controller action is not called.


Flattened Version

If I flatten my list of complex objects (XMLVariables) in the same ViewModel:

     public List<string> Names { get; set; }
     public List<string> Values { get; set; }

And map them in my View:

        @for (int i = 0; i < Model.XMLVariables.Count(); i++)
        {
            @Html.HiddenFor(m => Model.Names[i])
            @Html.TextBoxFor(m => Model.Values[i])
        }

Upon submission both lists are passed back with the correct values.


Controller Action:
    [HttpPost]
    public ActionResult Submit(ReportViewModel report, string cmd)
    { 
    }

Form Signature:

@using (Ajax.BeginForm("Submit", "Report", new AjaxOptions {LoadingElementId = "progress", OnSuccess="OnSuccess", OnBegin="OnBegin", OnComplete="OnComplete" }))
  • You need to share code of post controller action and also tell us what do you get in there when you submit the form – Chetan Mar 19 '18 at 16:45
  • @ChetanRanpariya "The view displays the variables just fine, but when I submit the form nothing happens. The controller action is not called." – Ryan Wilson Mar 19 '18 at 16:46
  • Yeah I don't think it's an issue with the controller action but I've included it. – Brandon Church Mar 19 '18 at 16:47
  • What did you observe in the network tab of developer tools window of your browser. Is it returning 404 when you submit form? – Chetan Mar 19 '18 at 16:49
  • @RyanWilson you think the controller parameters have nothing to do with why the controller action is not called? – maccettura Mar 19 '18 at 16:50
  • @maccettura "tell us what do you get in there when you submit the form" , he already stated what happens when he submits the form: "The controller action is not called." – Ryan Wilson Mar 19 '18 at 16:52
  • 1
    *when I submit the form nothing happens* - where is the definition for this mysterious form? Does it not submit because it doesn't exist, or did you just happen to leave the most important part of the code out of the question? – NightOwl888 Mar 19 '18 at 16:58
  • @NightOwl888 I added the form definition, but the only difference between the one that works vs. the one that doesn't work is a single property in the view model. All this does is call the "Submit" action on my "Report" controller. – Brandon Church Mar 19 '18 at 17:03
  • It would be great if you could provide a [Minimal, Complete, and Verifiable example](https://stackoverflow.com/help/mcve) instead of having a bunch of statements that nobody can copy and run. There is probably nothing wrong with the code you have posted, the issue is likely something that you *haven't* posted, and that makes this question unanswerable. See [Writing the Perfect Question](https://codeblog.jonskeet.uk/2010/08/29/writing-the-perfect-question/). – NightOwl888 Mar 19 '18 at 17:12
  • You need to use fiddled or some other network tracing tool to check what exact comes back when you submit the form. even If it is not reaching the controller action there should be some response. Or there is some JavaScript error which is preventing the form submit. Just `when I submit the form nothing happens` doesn't help much. – Chetan Mar 19 '18 at 17:12
  • @NightOwl888 I've given you the model, view, and controller so you could literally copy and run this for yourself. If you don't have any relevant advice on common pitfalls during complex enumerable binding then feel free to "help" someone else. I'm not going to post 10,000 lines of irrelevant code because you don't have the answer. – Brandon Church Mar 19 '18 at 17:20
  • @ChetanRanpariya I would certainly use Fiddler if I could.. but it isn't "approved" in the company I work for. – Brandon Church Mar 19 '18 at 17:22
  • I am not telling you to post code because I feel like it. I am trying to help you to write a complete [on-topic](https://stackoverflow.com/help/on-topic) question. But hey, if you don't want to follow the [rules](https://stackoverflow.com/help) here, I have no issue with voting to close it. This isn't a discussion forum, it is a Q & A site - the onus is on *you* to write a question that can be answered. – NightOwl888 Mar 19 '18 at 17:25
  • I would have tried your code if I were near my computer. You can also see network trace in developer tools of Google chrome and internet explorer. – Chetan Mar 19 '18 at 17:26
  • @NightOwl888 Feel free to let me know what you think is missing. Just saying it's incomplete isn't "helping" anyone. – Brandon Church Mar 19 '18 at 17:30
  • @ChetanRanpariya Thanks, I will give that a shot and post the results here. – Brandon Church Mar 19 '18 at 17:30
  • I am not just saying it is incomplete, I am posting *useful* links with helpful advice. It is not possible to tell you everything that you need to know to fix your question in the comments. But it should be plain to see that there is not enough code in your question to reasonably run anything to find out what is wrong. No submit button, the form tag is not before the form elements, lack of controller class, no routing config, etc. The question is pretty clear, but there is no way to solve the puzzle without the offending code in the body of the question. – NightOwl888 Mar 19 '18 at 17:37
  • 2
    @BrandonChurch The best way to make your code "complete" enough to solve the issue is give a complete controller class, view file and model. That means reduce your controller down to 2 actions, the `GET` and the `POST`. Reduce your model down to only the parts that are required to make the problem manifest itself. Reduce the view to a form tag with a submit button and the appropriate code for the inputs. That way I can literally create a new project, copy-paste your 3 files into there, hit run and see the problem happen (ie an MCVE). Then we can work on figuring out why it's happening. – Becuzz Mar 19 '18 at 18:19

1 Answers1

0

The problem was with my "XMLVariable" object. In case anyone has an issue binding custom objects like I did, it appears that MVC constructs a new ViewModel out of the data in the View, rather than passing back a modified version.

I wasn't getting an error for some reason, but the default model binder in MVC was creating XML objects from scratch and trying to call a parameterized constructor I had set up:

public class XMLVariable
{
    public string Name {get; set;}
    public string Value { get; set; }

    //MVC needed this parameterless constructor to bind View to new ViewModel
    public XMLVariable()
    { }

    //This was getting called before adding the parameterless constructor and failing
    public XMLVariable(string name, string value)
    {
        Name = name;
        Value = value;
    }
}

Thank you to ChetanRanpariya for pointing me to the network tracing tool that caught the issue.

If someone has the reputation for it, please mark this as a duplicate of this question which I found after the fact.

  • Duped as requested. But you also have another issue here, in that you have a hidden input and a textbox for the same property. The `DefaultModelBinder` will bind the first matching name/value pair and ignore the 2nd so your model will be bound to its original values (i,e the one in the hidden inputs) –  Mar 20 '18 at 00:32