ASP Core 2 empty POST request

11,998

Solution 1

The POST request needs to declare that the sent data is text/plain. Using the example with HttpClient:

client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("text/plain"));

This way, your API will be able to receive your JSON as a string content.

If instead you want to receive your content deserialized into the original model object, you need to add this header into your request:

client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

and change your controller to:

// POST: api/NativeClient
[HttpPost]
public async Task<IActionResult> Post([FromBody]yourClass class)
{
   [...]

Send JSON object to your API:

var Content = new StringContent(json, Encoding.UTF8, "application/json");
var response = await client.PostAsync("/api/NativeClient/", Content);

PostAsJsonAsync takes a C# Object as an input; it serializes it as a JSON string before sending it. Instead, PostAsync can take a JSON string to send.

see this Q&A httpclient-not-supporting-postasjsonasync-method-c-sharp

see this links for more info:

PostAsJsonAsync in C#

PostAsync

Solution 2

You should deserialize JSON to some model (class), because I believe you deserialize this string anyway somewhere in your code:

public class YourModel
{
    public bool _isValid { get; set; }
    public string _username { get; set; }
    public string _guid { get; set; }
    public DateTime _dt { get; set; }
    public string _ms { get; set; }
    // other properties from json
}

And your action:

[HttpPost]
public async Task<IActionResult> Post([FromBody] YourModel value)

Regarding to your app:

In your app you pass json as argument to PostAsJsonAsync(), but you need to pass object and it will be parsed to JSON:

var response = await client.PostAsJsonAsync("/api/NativeClient/", yourObject);

yourObject is instance of class which should be parsed to JSON.

After comment:

Also, try to change your app code to:

HttpClient client = new HttpClient();
client.BaseAddress = new System.Uri("http://localhost:51022/");
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

var httpContent = new StringContent(json, Encoding.UTF8, "application/json");    
var response = await client.PostAsync("/api/NativeClient/", httpContent);
Share:
11,998

Related videos on Youtube

alelom
Author by

alelom

Interoperability Lead @ BHoM

Updated on June 04, 2022

Comments

  • alelom
    alelom almost 2 years

    I've got a simple HTTP POST request, which I send to an ASP Core 2 application running in localhost with Kestrel. The received data is always null unless I use PostAsJsonAsync from another C# app.

    The json I'm sending has this form:

    {
      "_isValid": true,
      "_username": "test",
      "_guid": "f3f574eb-5710-43c5-a4ff-0b75866a72a7",
      "_dt": "2018-02-11T15:53:44.6161198Z",
      "_ms": "IsSelected"
      [...]
    }
    

    The ASP controller has this form:

    // POST: api/NativeClient
    [HttpPost]
    public async Task<IActionResult> Post([FromBody]string value)
    {
       [...]
    

    1. Case: sending with PostAsJsonAsync from another C# app

    In one case I'm successfully sending the request via another separate C# application which uses PostAsJsonAsync like this:

    HttpClient client = new HttpClient();
    client.BaseAddress = new System.Uri("http://localhost:51022/");
    client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
    
    var response = await client.PostAsJsonAsync("/api/NativeClient/", json);
    

    The controller receives the call and populates value successfully.

    2. Case: sending with an external REST client like Postman

    In another case I try to send the request via another REST client, such as Postman or Visual Studio Code through REST client extension:

    POST http://localhost:51022/api/NativeClient/ HTTP/1.1
    content-type: application/json; charset=utf-8
    
    {
      "_isValid": true,
      "_username": "gnappo",
      "_guid": "f3f574eb-5710-43c5-a4ff-0b75866a72a7",
      "_dt": "2018-02-11T15:53:44.6161198Z",
      "_ms": "IsSelected"
      [...]
    }
    

    Here the request is received by the controller, but the string value is always null.

    I've tried removing the [FromBody] tag, checking the request header, checking the json string in the body (which is exactly the same), and other things mentioned in the references below, but nothing works.

    What am I missing?


    Other tests tried/references

    Value are always null when doing HTTP Post requests

    Asp.net Core 2 API POST Objects are NULL?

    Model binding JSON POSTs in ASP.NET Core

  • alelom
    alelom about 6 years
    Thanks for your answer. If I do this, I'm able to use Postman and YourModel value gets correctly populated, but then the PostAsJsonAsync does not work anymore: I receive null. Any idea here?
  • Roman
    Roman about 6 years
    @alexlomba87, do you post same JSON?
  • alelom
    alelom about 6 years
    I already had MediaTypeWithQualityHeaderValue("application/json") set in my separate C# application. If I change the controller API in Post([FromBody] YourClass classValue), however, I'm able to get classValue only if I send a POST request through Postman; if I use PostAsJsonAsync then classValue results null again. Any idea?
  • alelom
    alelom about 6 years
    Your suggestion of using PostAsync instead of PostAsJsonAsync worked. To recap, I changed the signature of the controller including the YourModel insted of a string, then swapped the HttpClient method PostAsJsonAsync(json) into PostAsync(new StringContent(json, Encoding.UTF8, "application/json"). Thanks. Would you like to elaborate why it didn't work originally? I think it would be useful to have an explanation in the answer.
  • alelom
    alelom about 6 years
    I see you too like @Roma edited to suggest that I swap my PostAsJsonAsync into a PostAsync, and change my controller signature to use my Model class instead of a string. While both your answer work, I'm struggling to understand why my original solution didn't work for both types of HTTP call. Would you like to elaborate? Many thanks anyway.
  • Roman
    Roman about 6 years
    @alexlomba87, see edit, PostAsJsonAsync() should work now