15

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!

6 Answers 6

19

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.

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

3 Comments

this is the right answer to this question. there is no need to modify your server-side code, just send the right type of object it expects from the client.
No JSON.parse(jsonData) in ASP.NET MVC 5
@hexadecimal, JSON.parse isn't part of MVC but JavaScript, that's why I wrote client side. MVC is server side!
18

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

3 Comments

After changing action header and little changes in javascript it works!
This is not really an idiomatic solution as it will bypass the validation and binding capabilities of MVC. A much better solution is to add a JsonModelBinder and put this deserialization logic in there. If can be done by overriding a few methods in the DefaultModelBinder
If your values are inside a form, just serialize them and send them with ajax having the contentType of application/x-www-form-urlencoded; charset=UTF-8. If not, just wrap your input fields with a form action="javascript:void(0);"> so that you can serialize the form with say jQuery $.serialize() and use as the payload of the request.
3

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

Comments

2

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.

Comments

1

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);

Comments

-1
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(),
        }      


1 Comment

Your idea works great in my case!

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.