0

I confused after hours because I have an issue about getting null model in my api in a project same as another one that everything is ok in it!

About issue

Javascript:

var data = new FormData(),
    firstName = $('#FirstName').val(),
    lastName = $('#LastName').val();
data.append("FirstName", firstName);
data.append("LastName", lastName);

        var ajaxRequest = $.ajax({
            type: "POST",
            url: "/api/CRUD/AddPatient",
            contentType: "application/json",
            processData: false,
            data: data,
            success: function (xhr, data) {
                alert(data);
            },
            error: function (xhr, ajaxOptions, thrownError) {
                //handle error
            }
        });

API

    public string AddPatient(PatientBindingModel model)
    {
        try
        {
            PatientStore ps = new PatientStore();

            string ticks = DateTime.Now.Ticks.ToString();

            ps.Register(model);

            return "success";
        }
        catch (Exception ex)
        {
            string exMessage = ex.Message;
            return exMessage;
        }
    }

And the model passed into api controller is null at all!

Anyone have any idea? Thanks

Mehdi
  • 499
  • 1
  • 7
  • 31
  • Is this an MVC controller or ApiController ? Why are you using `FormData` object ? – Shyju Dec 17 '17 at 15:38
  • @Shyju The controller is ApiController, and I'm using formData because I do not submit data and I have no form in my view. – Mehdi Dec 17 '17 at 15:40
  • What's the definition of `PatientBindingModel` - if it doesn't match exactly, it won't bind. What if you set your parameters to `public string AddPatient(string FirstName, string LastName)` - does it come through then? What does your browser network tab show as the body on the POST? – freedomn-m Dec 17 '17 at 15:47
  • @freedomn-m PatientBindingModel has two string property of FirstName and LastName and some other properties, do you mean I should remove all other properties I don't need to use in this api controller? – Mehdi Dec 17 '17 at 15:54

2 Answers2

0

When making the ajax call, if you are specifying the contentType as "application/json", your data property value should be a JSON stringified version of your js object.

This should work.

var d = { FirstName: "Ross", LastName: "Geller" };

$.ajax({
    type: "POST",
    url: "/api/CRUD/AddPatient",
    contentType: "application/json",
    data: JSON.stringify(d)
}).done(function(data) {
    console.log(data);
}).fail(function(xhr, ajaxOptions, thrownError) {
    alert(thrownError);
});

the $.ajax method will send the request with application/json as the request Content-Type header. The model binder will read this request header and based on the value of that read the data you sent (from request body or request form data etc)

If you are sending a simple flat-lean view model object, you can skip explicitly specifying the contentType header and just send the js object as the data.

var d = { FirstName: "Ross", LastName: "Geller" };
$.ajax({
    type: "POST",
    url: "/api/CRUD/AddPatient",
    data: d
}).done(function (data) {
    console.log(data);
}).fail(function (xhr, ajaxOptions, thrownError) {
    alert(thrownError);
});

In this case, the $.ajax method will send the request with application/x-www-form-urlencoded as the request Content-Type header.

Now model binder will be able to map the posted data to your method parameter object, the PatientBindingModel object, Assuming that the FirstName and LastName are properties which are settable

public class PatientBindingModel
{
    public string FirstName { set; get; }
    public string LastName { set; get; }
}

Also , Usually you will have only one HttpPost method in your web api controller and you do not need to specify the method name in your request url. You can simply do something like /api/Customer (more of REST style resource url) and when you make a HttpPost type call to that url, the framework will direct that call to your corresponding method which is marked with [HttpPost] attribute

public class CustomerController : ApiController
{
    [HttpPost]
    public string AddPatient(PatientBindingModel model)
    {
        try
        {
            return "success : "+model.FirstName;
        }
        catch (Exception ex)
        {
            string exMessage = ex.Message;
            return exMessage;
        }
    }
}
Shyju
  • 214,206
  • 104
  • 411
  • 497
  • many thanks, Both of your solutions have tested and the model is null Strongly! :) I think the issue is something else then I'm trying to find differences between this project and another project that everything is ok there. – Mehdi Dec 18 '17 at 07:34
  • I just tested both methods and they work for me(Asp.net mvc5 app with web api 2 controllers). Compare it again and see what is missing. Also take a look at [How to pass json POST data to Web API method as an object?](https://stackoverflow.com/questions/20226169/how-to-pass-json-post-data-to-web-api-method-as-an-object) – Shyju Dec 18 '17 at 11:35
  • I know this solution is working as well but not in my project, as you said I have to find what is missing or wrong. Thanks for your help :) – Mehdi Dec 18 '17 at 13:10
0

Tru adding FromBody attribute to your PatientBindingModel parameter

[HttpPost]
public string AddPatient([FromBody] PatientBindingModel model)
{
    ...
}

On the client side try using JSON.stringifyand specify contentType and dataType:

var ajaxRequest = $.ajax({
    type: "POST",
    url: "/api/CRUD/AddPatient",
    contentType: "application/json",
    processData: false,
    data: JSON.stringify(data),
    contentType: 'application/json; charset=utf-8',
    dataType: 'json'
    success: function (xhr, data) {
        alert(data);
    },
    error: function (xhr, ajaxOptions, thrownError) {
        //handle error
    }
});
Dmitry Pavlov
  • 30,789
  • 8
  • 97
  • 121