15

I'm trying to POST JSON data to a Web Api method but the JSON data is not binding to the model.

Here's my model:

[DataContract]
public class RegisterDataModel
{
    [DataMember(IsRequired = true)]
    public String SiteKey { get; set; }

    [DataMember(IsRequired = true)]
    public String UserId { get; set; }

    [DataMember(IsRequired = true)]
    public String UserName { get; set; }
}

Here's my Web Api action:

    public class RegisterController : ApiController
    {
    public Guid Post([ModelBinder] RegisterDataModel registerDataModel)
    {
        if (!ModelState.IsValid)
        {
            throw new ModelStateApiException(ModelState);
        }
        var userProfileDataContract = userProfileBusinessLibrary.GetNewOne();
        userProfileDataContract.UserId = registerDataModel.UserId;
        userProfileDataContract.UserName = registerDataModel.UserName;

        var userKey = userProfileBusinessLibrary.Register(registerDataModel.SiteKey, userProfileDataContract);

        return userKey;
    }
    }

Before I added [ModelBinder], registerDataModel was null. After adding [ModelBinder], registerDataModel is a RegisterDataModel instance, but all of the property values are null.

Here's my Request via Fiddler:

http://local.testwebsite.com/api/register

Request Headers:
User-Agent: Fiddler
Host: local.testwebsite.com
Content-Length: 89
Content-Type: application/json; charset=utf-8:

Request Body:
{ 
 "SiteKey":"qwerty",
 "UserId": "12345qwerty", 
 "UserName":"john q"
}    

What am I missing to make my post data bind to the RegisterDataModel properties? Thanks for your help.

j0k
  • 22,600
  • 28
  • 79
  • 90
Tom Schreck
  • 5,177
  • 12
  • 68
  • 122
  • You might just need the `[Post]` attribute on your controller action. – McGarnagle Oct 06 '12 at 16:38
  • 1
    Thanks for reply, but adding [HttpPost] did not help. It's my understanding with WebApi that you do not need the http verb attributes because ASP.net MVC uses a convention of matching the verb to the controller action. – Tom Schreck Oct 06 '12 at 17:12

3 Answers3

14

Not related to the OP's problem, but the title of the question led me here when I used (public) fields instead of properties in the Model class (i.e. no {get; set;}). It turned out that this also causes the binding to fail.

Maybe helps someone.

robert4
  • 1,072
  • 15
  • 20
12

How are you creating the JSON request? Through Fiddler request builder? Try just the following in the request body.

{ 
 "SiteKey":"qwerty",
 "UserId": "12345qwerty", 
 "UserName":"john q"
}

I'm guessing 'Request Body:' is also part of your request body. Remove that and check.

abatishchev
  • 98,240
  • 88
  • 296
  • 433
  • I'm using Fiddler's composer to submit the json data to my web api. Here's a screen shot: http://screencast.com/t/x2IH6hp01rGQ – Tom Schreck Oct 06 '12 at 17:53
  • If I just remove the [ModelBinder], it works perfectly for me. I just copy pasted your code and tested it. One difference I'm seeing here is that your content-Length is 89. Mine is 64 for the exact same payload. That's why I'm guessing you are sending something extra like 'Request Body:' – Badrinarayanan Lakshmiraghavan Oct 06 '12 at 18:16
  • 4
    Oh, btw, there is an extra colon or a semi-colon next to utf-8 Content-Type: application/json; charset=utf-8: Remove that and try please – Badrinarayanan Lakshmiraghavan Oct 06 '12 at 18:20
  • It was a combination of having [ModelBinder] and the ":" typo. Thanks for your help. – Tom Schreck Oct 06 '12 at 18:36
1

In my case, app's requests are passed through a middleware called "API Manager" for authentication / authorization before forwarding to my .NET Web API. POST parameter isn't binded because, for some reason I'm no idea why, the "Content-Length" is emitted from the Headers.The reason is because, the default JsonMediaTypeFormatter always check requests' Content-Length before doing model binding, and if the Content-Length is not presented it will set the parameter to NULL.

Hung Nguyen
  • 489
  • 7
  • 20