0
votes

I have been working with Web API and found an interesting observation that I am not able to understand.

controller:

public class UserController: ApiController
{
   public void Post(MyViewModel data)
   {
      //data is null here if pass in FormData but available if its sent through Request Payload
   }
}

viewModel

public class MyViewModel{
        public long SenderId { get; set; }
        public string MessageText { get; set; }      
        public long[] Receivers { get; set; }
}

JS that is not working

var usr = {};
usr.SenderId = "10";
usr.MessageText = "test message";
usr.Receivers = new Array();
usr.Receivers.push("4");
usr.Receivers.push("5");
usr.Receivers.push("6");

$.ajax(
{ 
    url: '/api/User',
    type: 'POST',
    data: JSON.stringify(usr),
    success: function(response) { debugger; },
    error: function(error) {debugger;}
});

JS that is working

var usr = {};
usr.SenderId = "10";
usr.MessageText = "test message";
usr.Receivers = new Array();
usr.Receivers.push("4");
usr.Receivers.push("5");
usr.Receivers.push("6");

$.post( "/api/User", usr)
.done(function( data ) {
debugger;
});

So, if I pass on $.ajax with lots of other configuration like type, contentType, accept etc, it still don't bind model correctly but in case of $.post it works.

Can anybody explain WHY?

1
what is the content type that you are seeing in case of $.ajax based request and in case of $.post? Note that content type is important for web api as it tries to use the correct formatter based on this to deserialize the request content. - Kiran Challa
content type is application\json, I want to know why it works for request payload and not for form data. - Prashant Lakhlani

1 Answers

0
votes

Try looking at what gets POSTed when you try it with $.ajax (e.g. with Fiddler of F12 tools of your choice). It can very well be that jQuery passes the data as URL-encoded string rather that as JSON literal.

To fix the issue try specifying dataType together with contentType parameter. Also, I don't think you need JSON.stringify, just pass the JSON literal you're creating:

$.ajax({
  data: usr,
  dataType: 'json',
  contentType: 'application/json',
  /* The rest of your configuration. */
});

Here's the TypeScript method that we use in one of our projects (ko.toJSON returns a string representing a JSON literal passed as a method parameter):

public static callApi(url: string, type?: string, data?: any): RSVP.Promise {
    return new RSVP.Promise((resolve, reject) => {
        $.ajax('/api/' + url, {
            type: type || 'get',
            data: data != null ? ko.toJSON(data) : null,
            dataType: 'json',
            contentType: 'application/json; charset=utf-8',
            success: () => {
                resolve.apply(this, arguments);
            },
            error: () => {
                reject.apply(this, arguments);
            }
        });
    });
}

Hope this helps.