7

I am trying to get model binding with MVC3 and JSON working but I have had no luck... No matter what I do I seem to be getting a null model on the server.

Method Signature:

public ActionResult FilterReports(DealSummaryComparisonViewModel model)

Javascript UPDATED:

<script type="text/javascript" language="javascript">

    $(document).ready(function () {
        $('#filter-reports').click(filterReports);
    });

    function filterReports() {
        var filters = {
            SelectedRtoId: $('#SelectedRtoId').val(),
            SelectedPricingPointId: $('#SelectedPricingPointId').val(),
            SelectedLoadTypeId: $('#SelectedLoadTypeId').val(),
            SelectedBlockId: $('#SelectedBlockId').val(),
            SelectedRevisionStatusId: $('#SelectedRevisionStatusId').val()
        }
        var dealSummaries = { SelectedItemIds: $('#SelectedItemIds').val() }
        var model = { ReportingFilters: filters, DealSummaries: dealSummaries }

        $('#selected-items select option').attr("selected", "selected");
        $.ajax({
            url: '@Url.Action("FilterReports")',
            data: model,
            contentType: 'application/json',
            dataType: 'json',
            success: function (data) {
                alert(data);
            }
        }); 
    }
</script>

Models:

public class DealSummaryComparisonViewModel
{
    public ReportingFiltersViewModel ReportingFilters { get; set; }
    public LadderListViewModel DealSummaries { get; set; }
}

public class LadderListViewModel
{
    public MultiSelectList AvailableItems { get; set; }

    public int[] SelectedItemIds { get; set; }
    public MultiSelectList SelectedItems { get; set; }
}

public class ReportingFiltersViewModel
{
    public int? SelectedRtoId { get; set; }
    public ICollection<Rto> Rtos { get; set; }

    public int? SelectedPricingPointId { get; set; }
    public ICollection<PricingPoint> PricingPoints { get; set; }

    public int? SelectedLoadTypeId { get; set; }
    public ICollection<LoadType> LoadTypes { get; set; }

    public int? SelectedBlockId { get; set; }
    public ICollection<Block> Blocks { get; set; }

    public int? SelectedRevisionStatusId { get; set; }
    public ICollection<RevisionStatus> RevisionStatuses { get; set; }

    public bool? DealStatus { get; set; }
}

The model looks fine on the client side:

{"ReportingFilters":{
    "SelectedRtoId":"5",
    "SelectedPricingPointId":"20",
    "SelectedLoadTypeId":"55",
    "SelectedBlockId":"21",
    "SelectedRevisionStatusId":"11" 
},"DealSummaries":{
    "SelectedItemIds":["21","22","23","24","25"] 
}}

So why am I getting nothing back on the controller? This has been giving me trouble for the past two days so please help! Thanks!!

UPDATE I've updated my javascript section to what I am currently using. This section now returns the model to the controller with the ReportingFilers and DealSummaries objects, but all values within are null.

Does it possibly have something to do with the values being strings? If so, how can I fix this?

shuniar
  • 2,592
  • 6
  • 31
  • 38
  • What does the method look like? Is the method's input parameter named model? – Joe Sep 29 '11 at 13:19
  • can you post your actions signature here?? – Baz1nga Sep 29 '11 at 13:19
  • Have you tried debugging into MVC? There's source on the Microsoft symbol server so you should be able to put breakpoints in the JSON class (JsonModelBinding or similar) to see what's happening. You should also make sure the posted content type for your JSON data is correct too. – Rup Sep 29 '11 at 13:21

5 Answers5

4

Change your $.getJSON line to:

$.ajax({ 
   url: '@Url.Action("FilterReports")',
   data: JSON.stringify(viewModel),
   contentType: 'application/json',
   dataType: 'json',
   success: function (data) { alert(data); }
});

This way MVC knows that it is receiving JSON and will bind it to your model correctly.

Richard Dalton
  • 35,513
  • 6
  • 73
  • 91
  • Combining this with @IAbstractDownvoteFactory's answer I am one step closer, now I have the model object with the ReportingFilters and DealSummary objects, but now all of thier properties are null even though I am passing values to them. – shuniar Sep 29 '11 at 13:35
  • What happens when you try exactly what I posted? – Richard Dalton Sep 29 '11 at 13:50
  • I get a model with two null objects. – shuniar Sep 29 '11 at 13:54
  • Unfortunately, I can only accept one as the answer to my problem, so you get it because your post was the most helpful to solving my problem. Switching to the $.ajax from $.getJSON made the most significant contribution as the others built off of it. Thanks to everyone! – shuniar Sep 29 '11 at 20:44
  • Oh, no it won't. – SteveCav Jun 04 '19 at 07:03
3

Here's a few different things you could try:

  • Apparently you shouldn't use nullable properties in your objects if you want to use the DefaultModelBinder: ASP.NET MVC3 JSON Model-binding with nested class. So you could try making your ints not nullable or if that's not an option, implement IModelBinder yourself?

  • Have you marked your classes with the SerializableAttribute?

  • Try setting the type parameter in the ajax method to 'POST' - it will be using 'GET' by default.. type: 'POST'

  • Try explicitly setting the contentType parameter in the ajax method to this instead... contentType: 'application/json; charset=utf-8'

  • And finally, are you definitely using MVC 3, not MVC 2? I ask because MVC 3 has the JsonValueProviderFactory baked into the framework where as MVC 2 didn't so if you were using MVC 2 that might explain the problem you're having...

Community
  • 1
  • 1
codefrenzy
  • 246
  • 1
  • 6
  • Thanks! Updating it to a post and stringifying gives me all the data in my model in the controller, but now my postback isn't being reached... any sugguestions? – shuniar Sep 29 '11 at 16:03
  • Hmm, what do you mean your postback isn't being reached? If you put a breakpoint in your FilterReports Action and debug, does it stop? And your model no longer has nulls in it? Do you mean that the ajax callback isn't being reached? If so, what are you returning from your action? Have you tried specifying the 'error' parameter on the ajax method as well? – codefrenzy Sep 29 '11 at 20:47
  • I was referring to the ajax postback but I was able to figure it out. I wasn't returning JSON from my FilterReports method. – shuniar Sep 29 '11 at 20:50
2

Ok, replace:

{ model: JSON.stringify(viewModel) }

with

{ model: viewModel }

You're mixing objects with JSON strings, so jQuery will JSON.stringify the entire object. Which will double encode viewModel.

Joe
  • 80,724
  • 18
  • 127
  • 145
  • This is closer to working, the model object isn't null anymore, but the ReportingFilters and DealSummaries objects underneath it are. – shuniar Sep 29 '11 at 13:28
  • Can you replace your strings with ints? `["21","22","23","24","25"]` becomes `[21,22,23,24,25]` – Joe Sep 29 '11 at 13:30
  • Should removing the stringify achieve this? – shuniar Sep 29 '11 at 13:36
  • No, how are you building that javascript object? – Joe Sep 29 '11 at 13:48
  • You're right, it's stringified. I'm using the `ListBoxFor(m = m.SelectedItemIds, Model.SelectedItems)` which is the reason for the select all hack before the ajax query is called. How would I go about replacing the string values? – shuniar Sep 29 '11 at 13:51
1

here is what I would suggest, in your controllers action method should look as follows:

public JsonResult FilterAction(string model)
{
   var viewModel=new JavaScriptSerializer().Deserialize<DealSummaryComparisonViewModel>(model);
}

Also make sure your request is reaching the right action and look at Firebug for the same.

Baz1nga
  • 15,485
  • 3
  • 35
  • 61
0

Try this:

var filters = new Object();
filters.SelectedRtoId = $('#SelectedRtoId').val();
filters.SelectedPricingPointId =  $('#SelectedPricingPointId').val();
filters.SelectedLoadTypeId = $('#SelectedLoadTypeId').val();
filters.SelectedBlockId = $('#SelectedBlockId').val();
filters.SelectedRevisionStatusId = $('#SelectedRevisionStatusId').val();

var dealSummaries = new Object(); 
dealSummarties.SelectedItemIds = $('#SelectedItemIds').val();

var viewModel = new Object(); 
viewModel.ReportingFilters = filters;
viewModel.DealSummaries = dealSummaries;

$('#selected-items select option').attr("selected", "selected");
$.getJSON('@Url.Action("FilterReports")', { model: JSON.stringify(viewModel) }, function (data) {
            alert(data);
}); 
Martin
  • 11,031
  • 8
  • 50
  • 77