17

I am on ASP.Net MVC 3, and going by the feature list supported in at, i should be able to get default json model binding working out of the box. However i havent been successful in binding an array/collection from json to the action method parameter. Although I did get simple json object binding working right. Would greatly appreciate if an expert here could tell me what i am doing wrong.

Here is the code:

Server side code first:

//Action Method

 public JsonResult SaveDiscount(IList<Discount> discounts)
    {
       foreach(var discount in discounts)
       {
       ....
       }
    }

//View model

public class Discount
{
    string Sku{get; set;}
    string DiscountValue{get; set;}
    string DiscountType{get; set;}

}

//client side(jquery/js):

    var discount = {};
    var jsondatacoll = [];
    $('#discountgrid tr').each(function () {

        sku = $(this).find("td").eq(1).html();
        discValue = $(this).find('.discval').val();
        discType = $(this).find('.disctype').val();

        discount = { Sku: sku, DiscountType: discType, DiscountValue: discValue};
        jsondatacoll.push(discount);
        }
    })
    if (jsondatacoll.length > 0) {
        var catalogDiscount = JSON.stringify(jsondatacoll);

        $.ajax(
        {
            url: '/url/savediscount',
            type: 'POST',
            data: catalogDiscount,
            dataType: 'json',
            contentType: 'application/json; charset=utf-8',
            success: function (data, textStatus, jqXHR) {
                ...                   
            },
            error: function (objAJAXRequest, strError) {                 
               ...
            }
        }
     );   //ajax
    }

i did check the json payload in fiddler and it look like below:

[
    {"Sku":"sku1","DiscountType":"type1","DiscountValue":"10"},     
    {"Sku":sku2","DiscountType":"type1","DiscountValue":"12"}, 
    {"Sku":"sku3","DiscountType":"type2","DiscountValue":"40"}
]

And on the server side i do see the IList<Discount> discounts has been populated with 3 empty Discount objects - meaning the properties are null but the length of the discounts argument is 3.

4
  • 15
    Your model's properties should be marked public. Typo or oversight? Commented Mar 12, 2011 at 18:49
  • wow man! that was an oversight!!! would you want to enter this as answer so that i can mark it? :) Commented Mar 12, 2011 at 18:55
  • 5
    Thanks to the rest of your post being correct (other than those missing 'publics'), I noticed the contentType being set along with using JSON.stringify and it made all the difference. Struggled with this for hours! Thanks! Commented Sep 19, 2011 at 18:10
  • If you like the stuff mentioned in @DanielGill's comment check out this post on sending complex datatypes through ajax encosia.com/… Commented Jan 27, 2015 at 16:34

3 Answers 3

14

As Cresnet Fresh rightly pointed out in the comments to the question the model properties must be marked public.

So modifying Discount class as below resolved this.

public class Discount
{
    public string Sku{get; set;}
    public string DiscountValue{get; set;}
    public string DiscountType{get; set;}

}
Sign up to request clarification or add additional context in comments.

1 Comment

Can anyone explain (or better yet link to an explanation) as to WHY this has to be the case? I presume because first an empty object is created (hence need for parameterless constructor) and then the properties are set but I prefer to work on facts, not presumptions.
11

while @thanikkal answered this particular question, I had the same symptoms and a very similar setup.

instead of the public or { get; set; } in my models causing the model binding to not work it was actually my jQuery method! (RAWR!)

I was using $.post (which didn't work) instead of $.ajax.


Doesn't Work:

$.post("/Games/Action",
   { "userId": "1", "listName": [ { "fooId": "2", "barId": "99" } ] },
   'json',
   true
  );

The values are in the Form.Data[], but are not mapped properly.


Works:

 $.ajax(
    {
        url: '/Games/Action',
        type: 'POST',
        data: JSON.stringify({ userId: "1", listName: [ { fooId: 2, barId: 99 } ] }),
        dataType: 'json',
        contentType: 'application/json; charset=utf-8',
        success: function (data, textStatus, jqXHR)
        {
            console.log(data);
        },
        error: function (objAJAXRequest, strError)
        {
            console.log(data);
        }
    });

All values mapped correctly.


Lost a few hours to this one, hope this helps others.

2 Comments

I can confirm that the above is true. I was using $.post and whilst I was seeing an array being populated in my model, the values were all null. Switching to $.ajax has resolved the issue which seems strange. I was using MVC 4, jQuery 2.0.2
Just to expand on this a bit more, the $.post() function is shorthand for $.ajax() as explained here: api.jquery.com/jquery.post. But the call to $.ajax() does not include the contentType attribute. The above solution works for me, but not if I remove the contentType attribute, so it is this in particular which is needed (in my case at least).
-1

Your code looks fine.. But check this

  1. Routing settings.
  2. Put [HttpPost] attribute on SaveDiscount

and try this

var catalogDiscount = JSON.stringify( { discounts: jsondatacoll } );

that would give make right data binding.

1 Comment

thanks for answering here. as explained in the comments above, i missed marking my viewmodel properties public.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.