Dylan
Dylan

Reputation: 1306

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

Upvotes: 5

Views: 3251

Answers (2)

Darin Dimitrov
Darin Dimitrov

Reputation: 1038710

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.

Upvotes: 8

Dylan
Dylan

Reputation: 1306

I solved it using Nick Riggs Postify javascript code

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

Upvotes: 2

Related Questions