MVC3 & JSON.stringify() ModelBinding returns null model

27,128

Solution 1

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.

Solution 2

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...

Solution 3

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.

Solution 4

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.

Share:
27,128
shuniar
Author by

shuniar

I am a .NET developer and enjoy learning about and implementing new technologies.

Updated on August 03, 2022

Comments

  • shuniar
    shuniar over 1 year

    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
    shuniar over 12 years
    This is closer to working, the model object isn't null anymore, but the ReportingFilters and DealSummaries objects underneath it are.
  • Joe
    Joe over 12 years
    Can you replace your strings with ints? ["21","22","23","24","25"] becomes [21,22,23,24,25]
  • shuniar
    shuniar over 12 years
    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
    shuniar over 12 years
    Should removing the stringify achieve this?
  • shuniar
    shuniar over 12 years
    I recieve the same result as initializing them the other way.
  • Joe
    Joe over 12 years
    No, how are you building that javascript object?
  • Richard Dalton
    Richard Dalton over 12 years
    What happens when you try exactly what I posted?
  • shuniar
    shuniar over 12 years
    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
    shuniar over 12 years
    I get a model with two null objects.
  • shuniar
    shuniar over 12 years
    Yes, I've tried combiniations of them all, and it seems that the initialization doesn't make a differnece.
  • shuniar
    shuniar over 12 years
    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
    shuniar over 12 years
    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!
  • codefrenzy
    codefrenzy over 12 years
    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?
  • shuniar
    shuniar over 12 years
    I was referring to the ajax postback but I was able to figure it out. I wasn't returning JSON from my FilterReports method.
  • SteveCav
    SteveCav almost 5 years
    Oh, no it won't.