Posting form data to MVC Core API

In his post Model binding JSON POSTs in ASP.NET Core from 2016, Andrew Lock explains that in order to bind a JSON POST in ASP.NET Core, the [FromBody] attribute must be specified on the argument, like so:

[HttpPost]
public IActionResult CreateAccount([FromBody] Account account)
{
    // ...
}

With the ASP.NET Core 2.1 introduction of [ApiController], this is no longer required. Of importance here is that this attribute effectively infers the presence of the [FromBody] attribute when the type being bound is "complex" (which it is in your example). In other words, it's as though you have written the code as I demonstrated above.

In his post, Andrew also states the following:

In some cases you may need to be able to bind both types of data to an action. In that case, you're a little bit stuck, as it won't be possible to have the same end point receive two different sets of data.

Here, when referring to both types of data, Andrew is referring to both a JSON post and a form-based POST. He continues on to explain how to actually achieve the required result. Modifying his example for your purposes, you'd need to do something like the following:

// Form.
[HttpPost("FromForm")]
public IActionResult CreateAccountFromForm([FromForm] Account account)) =>
    DoSomething(account);

// JSON.
[HttpPost("FromBody")]
public IActionResult CreateAccountFromBody(Account account) =>
    DoSomething(account);

private IActionResult DoSomething(Account account) {
    // ...
}

In Andrew's example, the [FromBody] is explicit and the [FromForm] is implicit, but given the affect that [ApiController] has on the defaults, the modified example above flips that around.


See my answer here for a potential approach that allows for the same URL to be used for both FromForm and FromBody using a custom IActionConstraint.


If you want to get form data for the headr Content-Type:application/x-www-form-urlencoded) to your api controller then you have to put [FromForm] attribute in the action method like

    // POST: api/Create
    [HttpPost]
    public IActionResult CreateAccount([FromForm] Account account)
    {

    }

If you want to get form data for the header Content-Type:application/json to your api controller then you have to put [FromBody]/No attribute in the action method like

    // POST: api/Create
    [HttpPost]
    public IActionResult CreateAccount([FromBody] Account account)
    {

    }

Or

    // POST: api/Create
    [HttpPost]
    public IActionResult CreateAccount(Account account)
    {

    }

Make sure your request type is set to "application/json". I reproduced your code, and the method was not being called using Postman until I set the request type to application/json.

Edit: When I added the following to the headers in fiddler I was able to get fiddler to call my method as well:

Content-Type: application/json