2

For some reason, when I post this view model back to the controller and add in the model for binding, it ends up being null. The application that I am working with is a massive one. Also I haven't written much of the code so this model is massive so I will just add the parts that matter, but could other properties be preventing the model binding?

I do know that it has been working but in the last little bit it started not. Maybe it's not even something with the model, would just love some help debugging it.

POST Action:

[HttpPost]
public ActionResult Categories(int applicationId, SqsApplicationViewModel model)
{
    // Save away the ids they chose
    _sqsApplicationCategoryService.SaveCategories(applicationId, model.Display_Categories.Where(i => i.Selected).Select(i => i.CategoryId).ToList());

    // Complete the step
    _sqsApplicationStepService.CompleteStep(applicationId, SqsStep.Categories);

    return RedirectToAction("Documents");
}

View Model:

public class SqsApplicationViewModel : IMappable
{
    public int Id { get; set; }
    public int SupplierId { get; set; }
    public int? SqsApprovalLevelId { get; set; }

    // Other properties .....

    public List<SqsChosenCategoryViewModel> Display_Categories { get; set; }

    // Other properties .....
}


public class SqsChosenCategoryViewModel
{
    public int CategoryId { get; set; }
    public string Name { get; set; }
    public string CategoryAmountString { get; set; }
    public bool Selected { get; set; }

    public IList<SqsDocumentComplianceViewModel> Documents { get; set; }
}

View:

@using (Html.BeginForm())
{
    @Html.HiddenFor(m => m.Id)
    @if (Model.Display_Categories != null && Model.Display_Categories.Count() > 0)
    {
        for (var i = 0; i < Model.Display_Categories.Count; i++)
        {
            @Html.HiddenFor(m => m.Display_Categories[i].CategoryId)
            @Html.CheckBoxFor(m => m.Display_Categories[i].Selected)
            @Model.Display_Categories[i].Name
        }
    }
}

Also, the values being sent back in firebug are:

Id:1061
Display_Categories[0].CategoryId:4
Display_Categories[0].Selected:true
Display_Categories[0].Selected:false
Display_Categories[1].CategoryId:1
Display_Categories[1].Selected:false
Display_Categories[2].CategoryId:2
Display_Categories[2].Selected:false
Display_Categories[3].CategoryId:3
Display_Categories[3].Selected:false
Display_Categories[4].CategoryId:6
Display_Categories[4].Selected:true
Display_Categories[4].Selected:false
Display_Categories[5].CategoryId:8
Display_Categories[5].Selected:false
Display_Categories[6].CategoryId:10
Display_Categories[6].Selected:false
Display_Categories[7].CategoryId:7
Display_Categories[7].Selected:false
Display_Categories[8].CategoryId:9
Display_Categories[8].Selected:false
Display_Categories[9].CategoryId:11
Display_Categories[9].Selected:false
Display_Categories[10].CategoryId:5
Display_Categories[10].Selected:true
Display_Categories[10].Selected:false

-------------EDIT----------------

I tried using the following test models and it worked. Is it possible that another property in the Model could be hindering the binding? I added some random ones in these too and it still worked.

public class TestViewModel
{
    public int Id { get; set; }
    public IList<TestSubViewModel> Display_Categories { get; set; }
    public string TestProp { get { return "asdfasdfasdf"; } }
    public TestSubViewModel TestGetFirst { get { return     this.Display_Categories.FirstOrDefault(); } }
}

public class TestSubViewModel
{
    public int CategoryId { get; set; }
    public string Name { get; set; }
    public string CategoryAmountString { get; set; }
    public bool Selected { get; set; }

    public IList<SqsDocumentComplianceViewModel> Documents { get; set; }
}
Adam
  • 675
  • 5
  • 25
  • You need to show your view - if its not binding, the most common cause is because the view is not correct –  Jun 14 '15 at 23:58
  • Thanks @StephenMuecke I have updated the question with it and also with the form data being sent through in debug tools – Adam Jun 15 '15 at 00:11
  • 1
    Why do you have that `applicationId` parameter in the POST action? Also, remove the code that's irrelevant to the question (`SqsChosenCategoryViewModel` and the GET Categories action). – ataravati Jun 15 '15 at 00:20
  • Based on the form data, the `Id` and `Display_Categories` properties should bind. Are you claiming the model is `null`, or just some properties of `SqsApplicationViewModel` are `null`? –  Jun 15 '15 at 00:20
  • @ataravati, The `SqsChosenCategoryViewModel` is relevant :) –  Jun 15 '15 at 00:21
  • @StephenMuecke, you're right. Sorry about that! – ataravati Jun 15 '15 at 00:25
  • @ataravati The applicatoin id is from the route in the global file as a param {applicationId}. I also removed the GET, butyes the SqsChosenCategoryViewModel is relevant. Also Stephen, yes I am saying the model is actually 'null'. Could it be something else in the model that I am not showing here that could be hindering it or something? I have worked with MVC for a few years on and off and it has always worked. I also just created a TestViewModel with just the properties that are on this question and it worked?!?! – Adam Jun 15 '15 at 00:55
  • @StephenMuecke see above comment – Adam Jun 15 '15 at 00:55
  • 2
    Most common causes why the model would be `null` (as opposed to properties of the model) are that you have included an input for a complex property of the model or that you have a property in your model named `Model` (and included an input for it). The data you are posting has the correct name/value pairs and should bind. I suggest you comment out all the view code between the form tags (except the submit button) and then test by un-commenting one form control at a time –  Jun 15 '15 at 01:08
  • Thanks for all your help. Still no solution as yet. I don't believe either of the above that you mentioned is happening, looks like I'm just going to have to do some boring debugging for a while – Adam Jun 15 '15 at 05:06
  • Why some of the `Display_Categories` have two values for the `Selected` property (one true and one false)? – ataravati Jun 15 '15 at 17:59
  • 1
    @ataravati, That's because OP is using `@Html.CheckBoxFor()` which generates a checkbox and a hidden input. If the checkbox is checked it will post `true` and `false`, it not then it posts just `false`. The `DefaultModelBinder` ignores the second value if it exists. –  Jun 15 '15 at 23:17
  • @StephenMuecke, I didn't know that. Thanks! – ataravati Jun 16 '15 at 04:48
  • Do you use subversion of any kind ? Maybe you could show us the changes you've made.. – noobed Jun 16 '15 at 06:29

1 Answers1

1

So I'm just going to answer my own question, though it isn't solved as much as there is another way to do it.

I believe that when you typehint the model and it binds it, in the background it uses "TryUpdateModel()" and so I just called this in the controller and for some reason it worked. Not sure if I miss out on anything else by doing it this way, but it has worked for me.

Also you can debug what might be the issue by doing it this way by the following:

var model = new ViewModel();
 var isSuccess = TryUpdateModel(model);

 if (!isSuccess)
 {
     foreach (var modelState in ModelState.Values)
     {
        foreach (var error in modelState.Errors)
        {
           Debug.WriteLine(error.ErrorMessage);
        }
     }
 }

Taken from this post: How to find the exceptions / errors when TryUpdateModel fails to update model in asp.net mvc 3

Community
  • 1
  • 1
Adam
  • 675
  • 5
  • 25