Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MVC3 Json model binding not working when sent to server

I'm having a an odd problem with MVC3 and the model binding. When I post a JSON object to my controller the model binder can't create a typed object out of it at all. All the properties are the default (i.e. empty strings)

However if I create an instance on the server, and send it as a JSON action result the data on the wire looks identical.

I've tried with

$.ajaxSettings.traditional = true;

and it makes no difference

As an example if I post

{"RoutineName":"My new routine","Routines":[{"DayName":"Monday","Items":[21,31]}]}

The model binder fails, but coming from the server the data looks like

{"RoutineName":"Routine From Code","Routines":[{"DayName":"Monday","Items":[1,2]},{"DayName":"Tuesday","Items":[]}]}

The html used to generate this looks like

$('#submitRoutine').click(function () {
            var routines = [];
            $('.DayName').each(function (index, item) {
                var $item = $(item);
                var name = $item.html();
                var routineItems = [];
                $($item.attr('href')).find('.itemId').each(function () {
                    routineItems.push(parseInt($(this).val(), 10));
                });
                routines.push({
                    DayName: name,
                    Items: routineItems
                });
            });
            var routine = {
                RoutineName: $('#routineName').val(),
                Routines: routines
            };

            $.ajaxSettings.traditional = true;
            $.post('/Machine/CreateRoutine', JSON.stringify(routine),function (data) {},'json');
        });

So it looks like model binding from a typed object to JSON is ok, but coming back the other way isn't. Is there something I've missed?

The models are in F#

type RoutineDayViewModel() =
    let mutable _name = String.Empty
    let mutable _items = new ResizeArray<int>()

    member x.DayName with get() = _name and set value = _name <- value
    member x.Items with get() = _items and set value = _items <- value

type RoutineViewModel() =
    let mutable _name = String.Empty
    let mutable _routines = new ResizeArray<RoutineDayViewModel>()

    member x.RoutineName with get() = _name and set value = _name <- value
    member x.Routines with get() = _routines and set value = _routines <- value

EDIT: I've also tried with the following C# classes and get the same result

 public class RoutineDayViewModel
    {
        public string DayName { get; set; }
        public List<int> Items{ get; set; }
    }

    public class RoutineViewModel
    {
        public string RoutineName { get; set; }
        public List<RoutineDayViewModel> Routines { get; set; }
    }

I've also added the following to the global.asax

ValueProviderFactories.Factories.Add(new JsonValueProviderFactory())

Thanks

like image 945
Dylan Avatar asked Dec 06 '11 04:12

Dylan


2 Answers

You need to set the request content type to application/json if you intend to send a JSON formatted request which is what you are doing with the JSON.stringify method. So instead of:

$.post('/Machine/CreateRoutine', JSON.stringify(routine),function (data) {},'json');

you could use:

$.ajax({
    url: '/Machine/CreateRoutine',
    type: 'POST',
    contentType: 'application/json; charset=utf-8',
    data: JSON.stringify(routine),
    success: function (data) {

    } 
});

With this you don't need to set $.ajaxSettings.traditional nor you should be adding any JsonValueProviderFactory in your Global.asax as this provider is already added by default in ASP.NET MVC 3.

like image 114
Darin Dimitrov Avatar answered Nov 15 '22 03:11

Darin Dimitrov


I solved it using Nick Riggs Postify javascript code

http://www.nickriggs.com/posts/post-complex-javascript-objects-to-asp-net-mvc-controllers/

like image 35
Dylan Avatar answered Nov 15 '22 04:11

Dylan