17

I have a .net Core 2 API setup with some test function. (Visual Studio 2017)

Using postman I do a post with the raw data to that method, but the model is just blank? Why?

        // POST api/Product/test
        [HttpPost]
        [Route("test")]
        public object test(MyTestModel model)
        {
            try
            {
                var a = model.SomeTestParam;

                return Ok("Yey");
            }
            catch (Exception ex)
            {
                return BadRequest(new { message = ex.Message });
            }
        }

        public class MyTestModel
        {
            public int SomeTestParam { get; set; }

        }

enter image description here

enter image description here

Ruan
  • 3,969
  • 10
  • 60
  • 87

5 Answers5

30

You need to include the [FromBody] attribute on the model:

[FromBody] MyTestModel model

See Andrew Lock's post for more information:

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.

As noted by @anserk in the comments, this also requires the Content-Type header to be set to application/json.

Kirk Larkin
  • 84,915
  • 16
  • 214
  • 203
  • 6
    He also need to set the right content type in the request. It should be `application/json` and not `text`. – anserk Aug 24 '17 at 13:18
  • 1
    Adding the `ApiController` attribute to the class will also work and you then don't need to include `FromBody` on your parameters. – Neo Aug 13 '18 at 01:24
  • 2
    @Neo THANK YOU! I was missing the ApiController on my classes after I did a framework migration to .net core 3.1 and spend a good 4 hours trying to solve this!! – Greg Aug 27 '20 at 07:06
4

To add more information to the accepted answer:

There are three sources from which parameters are bound automatically without the use of an Attribute:

Form values: These are form values that go in the HTTP request using the POST method. (including jQuery POST requests).

Route values: The set of route values provided by Routing

Query strings: The query string part of the URI.

Note that Body is NOT one of them (though I think it should be).

So if you have values that need to be bound from the body, you MUST use the attribute binding attribute.

This tripped me up yesterday as I assumed that parameters from the Body would be bound automatically.

The second minor point is that only one parameter can be bound to the Body.

There can be at most one parameter per action decorated with [FromBody]. The ASP.NET Core MVC run-time delegates the responsibility of reading the request stream to the formatter. Once the request stream is read for a parameter, it's generally not possible to read the request stream again for binding other [FromBody] parameters.

Thus if there is more than one parameter you need, you need to create a Model class to bind them:

public class InputModel{
   public string FirstName{get;set;}
   public string LastName{get;set;}
}

[HttpPost]
public IActionResult test([FromBody]InputModel model)...

The Docs

Greg Gum
  • 33,478
  • 39
  • 162
  • 233
1

Alternatively, add the [ApiController] attribute to your controller.

This has annoyingly affected me so many times (months apart) that I want this answer visible.

reckface
  • 5,678
  • 4
  • 36
  • 62
0

I deal with this issue for some hours. This problem stems from several reasons. Let's consider the request is Reactjs (javascript) and backend (API) is Asp .Net Core.

in the request, you must set in header Content-Type:

Axios({
            method: 'post',
            headers: { 'Content-Type': 'application/json'},
            url: 'https://localhost:44346/Order/Order/GiveOrder',
            data: order,
          }).then(function (response) {
            console.log(response);
          });

and in the backend (Asp .net core API) u must have some setting:

1. in Startup --> ConfigureServices:

#region Allow-Orgin
            services.AddCors(c =>
            {
                c.AddPolicy("AllowOrigin", options => options.AllowAnyOrigin());
            });
            #endregion

2. in Startup --> Configure before app.UseMvc() :

app.UseCors(builder => builder
                .AllowAnyOrigin()
                .AllowAnyMethod()
                .AllowAnyHeader()
                .AllowCredentials());

3. in the controller before action:

[EnableCors("AllowOrigin")]
Mahdi Jalali
  • 323
  • 3
  • 3
0

In my case I had { get; set; } missing in my .cs model which results in an object with all members null on POST.

JF Gagnon
  • 220
  • 3
  • 8