2013-05-21 17 views
28

Ich posten JSON auf einem WebAPI-Controller, aber die Eigenschaften im Modell werden nicht gebunden.WebAPI POST [FromBody] nicht verbindlich

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

Die rohe Anfrage lautet wie folgt:

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} 

Jedes Beispiel, das ich mich finden sagt dies funktionieren sollte, aber model.Id == null.

Allerdings, wenn ich die JSON ändern:

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

alles bindet richtig.

Dies gilt nicht korrekt zu sein scheint. Ich nehme an, ich könnte JObject als Parameter annehmen und es manuell binden, aber es fühlt sich an, als ob das oben genannte Just Work (tm)?

Update:

Ich habe die Methode geändert, das Modell zurückzukehren, und ich immer noch null erhalten.

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

Und die Antwort:

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 
+1

Können Sie die Klassendefinition für Benutzer anzeigen? –

+3

#facepalm. Kein parameterloser Konstruktor. Prost für die aufschlussreiche Ausnahme .net! – mattdwen

+1

Gibt es so etwas wie Schande, eine Frage zu löschen? – mattdwen

Antwort

5

Mein Benutzermodell hatte keinen parameterlose Konstruktor.

+0

Das löste mein Problem auch. Ich hatte einen Konstruktor, der Parameter benötigte, und er erhielt null für alle Argumente. Das Hinzufügen eines leeren, parameterlosen Konstruktors behob das Problem. –

17

Folgende funktioniert perfekt für mich in Ordnung:

Modell:

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; 
    } 
} 

Anfrage:

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} 

Antwort:

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} 

Wie Sie alles sehen können, gebunden ist schön und gut, ohne den User Präfix in der Anforderung JSON Nutzlast.

Seien Sie vorsichtig mit der model.Id, denn id könnte eine besondere Bedeutung haben, wenn Sie es in Ihren Routendefinitionen als Teil der Route verwenden. Verwechseln Sie die 2 Dinge nicht (Routenparameter und solche, die aus der Nutzlast des Anfragekörpers kommen).

+0

Ich habe die Methode geändert, um das POSTed-Modell zurückzugeben, wie in Ihrem Beispiel, aber ich empfange immer noch null – mattdwen

+2

Folgen Sie meinem Beispiel Schritt für Schritt Erstellen Sie eine neue ASP.NET MVC 4-Anwendung mithilfe der Basisvorlage ein Modell (wie in meiner Antwort gezeigt) .Fügen Sie einen API-Controller (wie in meiner Antwort gezeigt). Verwenden Sie Fiddler und rufen Sie diesen Controller mit der Nutzlast in meiner Antwort.Es funktioniert! Ich habe das Millionen Male getan und hatte nie Alle Probleme –

+2

Dies ist die richtige Antwort.Das Problem ist, dass das Label {User:} in der Anfrage nicht angegeben werden sollte, das User-Objekt selbst sollte der Stamm sein –

24

Sie vermissen die Content-Type Header in Ihrer Anfrage.

Leider, auch wenn Sie nach ModelState gesucht haben, werfen wir keine Fehlerinformationen auf. Die gute Nachricht ist jedoch, dass dieses Verhalten für unsere kommende Version behoben wurde und Sie eine 415-Statuscode-basierte Antwort sehen würden.

Die Web-API benötigt den Content-Type-Header, um den richtigen Formatierer zu finden, um den Body für den Parameter der Aktion zu deserialisieren.

+1

Ist 'Content-Type: application/json; charset = utf-8' nicht gültig? – mattdwen

+1

h mm..von Ihrem ursprünglichen Beitrag oben, es war kein Content-Type-Header darin und es hat so etwas wie 'Content-Length :: application/json, text/plain, */*' ..was das ein Tippfehler? .. Haben Sie auch versucht, zu überprüfen, ob Sie irgendwelche Modellzustandsfehler haben ... Sie könnten diese Prüfung hinzufügen und sehen 'if (! ModelState.IsValid) { werfen neue HttpResponseException (Request.CreateErrorResponse (HttpStatusCode.BadRequest, this.ModelState)); } ' –

+0

Obwohl ein etwas anderes Thema, Adding 'contentType': 'application/json; charset = utf-8 'zu meinem jquery ajax post half. Also hat contentType einen großen Unterschied für mich gemacht. Es wurde im Controller korrekt geroutet, aber der Datenparameter war immer leer (bis jetzt). –

Verwandte Themen