Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WebAPI POST [FromBody] not binding

I'm posting JSON to a WebAPI controller, but the properties on the model are not being bound.

public void Post([FromBody] Models.Users.User model) {
    throw new Exception(model.Id.ToString());
}

The raw request is as follows:

POST http://diva2.local/siteapi/User HTTP/: diva2.local
Connection: keep-alive
Content-Length:: application/json, text/plain, */*
Origin: http://diva2.local
X-Requested-With: XMLHttpRequest
User-Agent: Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.: application/json;charset=UTF: http://diva2.local/Users
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=: ISO-8859-1,utf-8;q=0.7,*;q=: .ASPXAUTH=4; __RequestVerificationToken=Rp_hUysjwCjmsxw2

{"Id":3,"FirstName":"DIVA2","LastName":"User1","Username":"diva1","IsApproved":true,"IsOnlineNow":true,"IsChecked":true}

Every example I can find tells me this should work, but model.Id == null.

However, if I change the JSON to:

{User: {"Id":3,"FirstName":"DIVA2","LastName":"User1","Username":"diva1","IsApproved":true,"IsOnlineNow":true,"IsChecked":true}}

everything binds correctly.

This doesn't seem correct. I guess I could accept JObject as the parameter, and bind it up manually, but it feels like the above should Just Work (tm)?

Update:

I've changed the method to return the model, and I still receive null.

public Models.Users.User Post(Models.Users.User user) {
    return user;
}

And the response:

HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Content-Type: application/json; charset=utf-8
Expires: -1
Server: Microsoft-IIS/8.0
X-AspNet-Version: 4.0.30319
X-MiniProfiler-Ids: ["a0fab514-d725-4d8f-9021-4931dc06ec4a","fdeeb9a8-9e36-41d8-91d3-5348e880e193","c1b4cc86-d7c3-4497-8699-baac9fa79bf1"]
X-Powered-By: ASP.NET
Date: Tue, 21 May 2013 09:06:00 GMT
Content-Length: 4

null
like image 901
mattdwen Avatar asked May 21 '13 08:05

mattdwen


3 Answers

You are missing the Content-Type header in your Request.

Unfortunately even if you had checked for ModelState, we are not throwing any error information. However, the good news is that this behavior has been fixed for our coming release and you would see a 415 status code based response.

Web API requires the Content-Type header to find out the right formatter to deserialize the body to the parameter on the action.

like image 118
Kiran Avatar answered Nov 19 '22 16:11

Kiran


The following works perfectly fine for me:

Model:

public class User
{
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Username { get; set; }
    public bool IsApproved { get; set; }
    public bool IsOnlineNow { get; set; }
    public bool IsChecked { get; set; }
}

Controller:

public class ValuesController : ApiController
{
    public User Post(User user)
    {
        return user;
    }
}

Request:

POST http://example.com/api/values HTTP/1.1
Connection: keep-alive
Accept: application/json, text/plain, */*
Content-Type: application/json;charset=UTF-8
Host: localhost:8816
Content-Length: 125

{"Id":3,"FirstName":"DIVA2","LastName":"User1","Username":"diva2user1","IsApproved":true,"IsOnlineNow":true,"IsChecked":true}

Response:

HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Content-Type: application/json; charset=utf-8
Expires: -1
Server: Microsoft-IIS/8.0
Date: Tue, 21 May 2013 08:59:02 GMT
Content-Length: 125

{"Id":3,"FirstName":"DIVA2","LastName":"User1","Username":"diva2user1","IsApproved":true,"IsOnlineNow":true,"IsChecked":true}

As you can see everything is bound fine and dandy without the User prefix in the request JSON payload.

Be careful with the model.Id, because id might have a special meaning if you are using it in your route definitions as being part of the route. Do not confuse the 2 things (route parameters and those coming from the request body payload).

like image 44
Darin Dimitrov Avatar answered Nov 19 '22 15:11

Darin Dimitrov


My user model did not have a parameter-less constructor.

like image 14
mattdwen Avatar answered Nov 19 '22 15:11

mattdwen