33

I have the following WEB API method, and have a SPA template with Angular:

[HttpPost]
public IActionResult Post([FromBody]MyViewModel model)

I thought, based on this topic, there is no need to use [FromBody] here, since I want to read the value from the message body, so there is no need to override the default behavior, but, if I don't use [FromBody], the model that is coming from Angular is null. I'm really confused, why should I use [FromBody], since I have used the default behavior?

Nkosi
  • 215,613
  • 32
  • 363
  • 426
  • You have to use `[FromBody]` if you are using HttpPost from your angular side to call the api in .net Core – Niladri Jun 09 '18 at 06:58
  • @Niladri OK. I know. But Why? –  Jun 09 '18 at 06:59
  • Check the link given by stephen below ... it's due to json model binding in .NET Core. For query string you have to use `[FromQuery]` with httpget. – Niladri Jun 09 '18 at 07:00
  • 1
    In ASP.NET Core 2.1, this attribute may be optional if it's clear the body is assigned to that parameter in a Post. – Ray Jun 09 '18 at 07:02

3 Answers3

30

For anyone seeing this issue .net core 3 - you need to add the [ApiController] to the controller where you extend ControllerBase. The [FromBody] is only needed if you're doing an MVC controller.

This causes the body to get automatically processed in the way you're expecting.

Microsoft documentation for the ApiController attribute

Community
  • 1
  • 1
Rob
  • 563
  • 7
  • 8
  • I have seen the same problem in two projects, is there something I missed in the migration documentation from 2.1 -> 2.2 -> 3.0 -> 3.1 – Mathias Haugsbø Dec 11 '19 at 13:55
  • are it mean i need add [ApiController] in any route O_o it's so much!( – xSx Dec 19 '19 at 15:37
  • 1
    I was looking all over for this! Thanks. I have a .NET Core Web API 3.1 project and didn't add [ApiController] to my controller. Then I needed [FromBody]. Added [ApiController] now it works without [FromBody]. – duyn9uyen Apr 01 '20 at 21:43
  • I owe you a complete-day! You've saved me!! – Onur Omer Dec 29 '20 at 16:56
  • This is not correct. It has to do with which content-type is being used. In order to bind the JSON correctly in ASP.NET Core, you must modify your action to include the attribute [FromBody] on the parameter. This tells the framework to use the content-type header of the request to decide which of the configured IInputFormatters to use for model binding. https://andrewlock.net/model-binding-json-posts-in-asp-net-core/ – Daniel Frost Feb 02 '21 at 18:15
13

The question you linked to is referring to web-api. You are using core-mvc which has been re-written to merge the pipelines for the previous mvc and web-api versions into one Controller class.

When posting json (as apposed to x-www-form-urlencoded), the [FromBody] attribute is required to instruct the ModelBinder to use the content-type header to determine the IInputFormatter to use for reading the request.

For a detailed explanation of model binding to json in core-mvc, refer Model binding JSON POSTs in ASP.NET Core.

2

And here's an alternate approach assuming you need to support both [FromForm] and [FromBody] in your Controller API…

Front-End (Angular Code):

forgotPassword(forgotPassword: ForgotPassword): Observable<number> {
  const params = new URLSearchParams();
  Object.keys(forgotPassword).forEach(key => params.append(key, forgotPassword[key]));
  return this.httpClient.post(`${this.apiAuthUrl}/account/forgotpassword`, params.toString(), { headers: { 'Content-Type': 'application/x-www-form-urlencoded' } });
}

Back-End (C# Code):

[AllowAnonymous]
[HttpPost("[action]")]
public async Task<IActionResult> ForgotPassword(ForgotPasswordViewModel model) { }

Now your signature can remain the same so it can support both.

And another more permanent approach I thought about while addressing.

https://benfoster.io/blog/aspnet-core-customising-model-binding-conventions.

Hope it helps someone!

Tim Harker
  • 2,307
  • 1
  • 14
  • 27