Piotr Czarnecki
Piotr Czarnecki

Reputation: 1688

ASP.NET MVC 4 JSON Binding to the View Model - Nested object error

I have got the problem with json binding to the view model. Here is my code:

part of my ViewModels (AddressViewModel has more properties):

public class AddressViewModel
{
        [Display(Name = "Address_Town", ResourceType = typeof(Resources.PartyDetails))]
        public string Town { get; set; }

        [Display(Name = "Address_Country", ResourceType = typeof(Resources.PartyDetails))]
        public Country Country { get; set; }
}

public class Country : EntityBase<string>
{
        public string Name { get; set; }

        protected override void Validate()
        {
            if (string.IsNullOrEmpty(Name))
            {
                base.AddBrokenRule(new BusinessRule("CountryName", "Required"));
            }
        }
}

Javascript:

$(document).on("click", "#addAddress", function () {
            var jsonData = {
                "Town": $('#txt-Town').val(),
                "District": $('#txt-District').val(),
                "Street": $('#txt-Street').val(),
                "PostCode": $('#txt-PostCode').val(),
                "FlatNumber": $('#txt-FlatNumber').val(),
                "PremiseName": $('#txt-PremiseName').val(),
                "PremiseNumber": $('#txt-Premisenumber').val(),
                "Country": {
                    "Name": $('#txt-Country').val(),
                }
            };
            var addressData = JSON.stringify(jsonData);
            $.ajax({
                url: '/Customer/SaveAddress',
                type: "POST",
                dataType: "json",
                contentType: "application/json; charset=utf-8",
                data: addressData,
                success: function (result) {
                    $("#addIndividualAddressDialog").data("kendoWindow").close();
                },
                error: function (result) {
                    alert("Failed");
                }

            });
        });

Header of controller:

[HttpPost]
 public ActionResult SaveAddress(AddressViewModel addressViewModel)

This is what I see with firebug:

enter image description here

And this is what I see in VS:

enter image description here

As you can see Plain properties are binded correct but my nested object (Country) is null. I read a lot of different articles and I still don't know what I'm doing wrong. Help me please!

Upvotes: 15

Views: 48133

Answers (6)

Monti
Monti

Reputation: 21

You must reference to Country object inside jsonData variable. The JSON POST binding will work correctly.

Old code:

    var jsonData = {
        "Town": $('#txt-Town').val(),
        "District": $('#txt-District').val(),
        "Street": $('#txt-Street').val(),
        "PostCode": $('#txt-PostCode').val(),
        "FlatNumber": $('#txt-FlatNumber').val(),
        "PremiseName": $('#txt-PremiseName').val(),
        "PremiseNumber": $('#txt-Premisenumber').val(),
        "Country": {
            "Name": $('#txt-Country').val(),
        }

New code:
    var jsonData = {
        "Town": $('#txt-Town').val(),
        "District": $('#txt-District').val(),
        "Street": $('#txt-Street').val(),
        "PostCode": $('#txt-PostCode').val(),
        "FlatNumber": $('#txt-FlatNumber').val(),
        "PremiseName": $('#txt-PremiseName').val(),
        "PremiseNumber": $('#txt-Premisenumber').val(),
        "Country.Name": $('#txt-Country').val(),
        }      


Upvotes: -1

Thomas
Thomas

Reputation: 34188

Sorry to answer for old thread.here you could work with JsonResult instead of ActionResult

this is your signature

 [HttpPost]
 public ActionResult SaveAddress(AddressViewModel addressViewModel)

it should look like

[HttpPost]
 public JsonResult SaveAddress(AddressViewModel addressViewModel)
 {
    return Json(status);
 }

the advantage would be if you use JsonResult instead of ActionResult that u do not need to Deserialize

here is the link http://codeforcoffee.org/asp-net-mvc-intro-to-mvc-using-binding-json-objects-to-models/ from this link you can get the idea.

Upvotes: 2

Rap
Rap

Reputation: 7292

Actually the best option is just to remove the

var addressData = JSON.stringify(jsonData);

line and send jsonData itself. ASP.NET MVC will auto-bind it if it is an actual object and not just a string.

Occam's Razor

Upvotes: 3

user3559829
user3559829

Reputation: 11

OR you can use JsonConvert.DeserializeObject<>();

following is the code to deserialize the JSON.stringify() result

IList<AddressViewModel> modelObj = JsonConvert.DeserializeObject<IList<AddressViewModel>>(addressViewModel);

instead of

JavaScriptSerializer().Deserialize<IList<AddressViewModel>>(addressViewModel);

Upvotes: 1

Shahar G.
Shahar G.

Reputation: 1510

You can keep your existing ActionMethod untouched without the need of json serializing: In the client side create an object from your json:

JSON.parse(jsonData)

and send that in the $.ajax data property.

Or, instead of creating json, create an object:

var dataObject = new Object();
dataObject.Town = $('#txt-Town').val();
dataObject.District = $('#txt-District').val();
...

And again, send that object in the $.ajax data property.

Upvotes: 19

Amin Saqi
Amin Saqi

Reputation: 18977

The problem is from your action method parameter:

[HttpPost]
public ActionResult SaveAddress(AddressViewModel addressViewModel)

As you use JSON.stringify(), you send a string to your controller, not an object! So, you need to do some works to achive your goal:

1) Change your action method parametter:

[HttpPost]
public ActionResult SaveAddress(string addressViewModel)

2) Deserialize that string to an object - that is AddressViewModel:

IList<AddressViewModel> modelObj = new 
JavaScriptSerializer().Deserialize<IList<AddressViewModel>>(addressViewModel);

So, your final action method should be like the following:

[HttpPost]
public ActionResult SaveAddress(string addressViewModel)
{
    IList<AddressViewModel> modelObj = new 
    JavaScriptSerializer().Deserialize<IList<AddressViewModel>>(addressViewModel);

    // do what you want with your model object ...
}

Upvotes: 18

Related Questions