MVC3 POST model binding not working for particular complex model

613 views Asked by At

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; }
}
1

There are 1 answers

0
Adam On

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