2

I have just started learning WebAPI today and I can't figure out why "account" is always null.

Request

Content-Type: application/json; charset=utf-8
Request-Body: {"account":{"email":"awd","password":"awad","isNewsletterSubscribed":false}}

WebAPI

 public class AccountsController : ApiController
    {
        public void Post([FromBody] string account)
            {
                    // account is null
            }
    }

Shouldn't account contain a json string in this case?

1 Answer 1

8

Shouldn't account contain a json string in this case?

That would depend on the specific Content-Type request header you set when you send the request. For example if you used application/x-www-form-urlencoded which is the default then your request body payload must have looked like this:

={"account":{"email":"awd","password":"awad","isNewsletterSubscribed":false}}

Notice the = character at the beginning. That's one of the biggest weirdest things I have ever encountered. Since you can bind only one parameter from the body if the request the Web API doesn't expect a parameter name, but just the value.

This being said, your request payload looks more like a JSON. So it would make far more sense to design a view model and use Content-Type: application/json when sending the request. Binding a JSON object to a string is not common practice.

So:

public class UserViewModel
{
    public string Email { get; set; }
    public string Password { get; set; }
    public bool IsNewsletterSubscribed { get; set; }
}

public class AccountViewModel
{
    public UserViewModel Account { get; set; }
}

and then your controller action will simply take the view model as parameter. In this case yo udon't need to decorate it with the [FromBody] attribute because by convention in Web API the default model binder will attempt to bind complex types from the body of the request:

public class AccountsController : ApiController
{
    public HttpResponseMessage Post(AccountViewModel model)
    {
        // work with the model here and return some response
        return Request.CreateResponse(HttpStatusCode.OK);
    }
}

Also notice that since HTTP is a request/response protocol it makes much more sense to have your Web API controller actions return response messages as shown in my example rather than just having some void methods. This makes the code more readable. You immediately understand how the server will respond and with what status code to the specified request.

Sign up to request clarification or add additional context in comments.

4 Comments

the request header is "application/json; charset=utf-8"
Alright, see my updated answer for the proper way to design this using a view model that will match the JOSN structure.
It works, thank you! One last question. Why do I have to specify an additional AccountViewModel class with a property Account? Is this somehow integrated into the famework?
That's because of the form of your JSON object: It has an account property so you need to wrap everything in an outer class with a property with the same name. The model binder will attempt to match the exact same structure when performing the binding. If your request body payload looked like this: {"email":"awd","password":"awad","isNewsletterSubscribed":false} then you could have directly used the UserViewModel as parameter.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.